`IFS = read .. '에서 IFS는 왜 효과가 없습니까?


12

나는 절대적으로 잘못되었을 수도 있지만 IFS를 사전 / 완료 목록 의 명령 중 하나로 설정해 도 아무런 효과가 없다는 것이 설득력이 있습니다. 아래 스크립트에 표시된 모든 예제에서
외부 IFS ( while구조 외부 )가 우선합니다.

무슨 일이야? 이 상황에서 IFS의 기능에 대한 잘못된 아이디어를 얻었습니까? 배열 분할 결과가 "예상"열에 표시된 것과 같을 것으로 예상했습니다.


#!/bin/bash
xifs() { echo -n "$(echo -n "$IFS" | xxd -p)"; } # allow for null $IFS 
show() { x=($1) 
         echo -ne "  (${#x[@]})\t |"
         for ((j=0;j<${#x[@]};j++)); do 
           echo -n "${x[j]}|"
         done
         echo -ne "\t"
         xifs "$IFS"; echo
}
data="a  b   c"
echo -e "-----   --  -- \t --------\tactual"
echo -e "outside        \t  IFS    \tinside" 
echo -e "loop           \t Field   \tloop" 
echo -e "IFS     NR  NF \t Split   \tIFS (actual)" 
echo -e "-----   --  -- \t --------\t-----"
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while         read; do echo -ne '\t 1'; show "$REPLY"; done 
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=    read; do echo -ne '\t 2'; show "$REPLY"; done 
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b   read; do echo -ne '\t 3'; show "$REPLY"; done
IFS=" ";      xifs "$IFS"; echo "$data" | while         read; do echo -ne '\t 4'; show "$REPLY"; done 
IFS=" ";      xifs "$IFS"; echo "$data" | while IFS=    read; do echo -ne '\t 5'; show "$REPLY"; done 
IFS=" ";      xifs "$IFS"; echo "$data" | while IFS=b   read; do echo -ne '\t 6'; show "$REPLY"; done
IFS=;         xifs "$IFS"; echo "$data" | while         read; do echo -ne '\t 7'; show "$REPLY"; done 
IFS=;         xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne '\t 8'; show "$REPLY"; done 
IFS=;         xifs "$IFS"; echo "$data" | while IFS=b   read; do echo -ne '\t 9'; show "$REPLY"; done
IFS=b;        xifs "$IFS"; echo "$data" | while IFS=    read; do echo -ne '\t10'; show "$REPLY"; done
IFS=b;        xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne '\t11'; show "$REPLY"; done
echo -e "-----   --  -- \t --------\t-----"

산출:

-----   --  --   --------       actual   
outside           IFS           inside                assigned   
loop             Field          loop    #              inner
IFS     NR  NF   Split          IFS     #  expected    IFS
-----   --  --   --------       -----   #  ---------  --------
20090a   1  (3)  |a|b|c|        20090a  #                              
20090a   2  (3)  |a|b|c|        20090a  #  |a  b   c|  IFS=
20090a   3  (3)  |a|b|c|        20090a  #  |a  |   c|  IFS=b
20       4  (3)  |a|b|c|        20      #                          
20       5  (3)  |a|b|c|        20      #  |a  b   c   IFS=
20       6  (3)  |a|b|c|        20      #  |a  |   c|  IFS=b
         7  (1)  |a  b   c|             #                          
         8  (1)  |a  b   c|             #  |a|b|c|     IFS=" "
         9  (1)  |a  b   c|             #  |a  |   c|  IFS=b
62      10  (2)  |a  |   c|     62      #  |a  b   c|  IFS=
62      11  (2)  |a  |   c|     62      #  |a|b|c|     IFS=" "
-----   --  --   --------       -----      ---------   -------                        

답변:


17

(죄송합니다, 긴 설명)

예, IFS변수 in while IFS=" " read; do …은 나머지 코드에는 영향을 미치지 않습니다.

먼저 쉘 명령 행에 두 가지 다른 종류의 변수가 있다는 것을 명심합시다.

  • 쉘 변수 (쉘에만 존재하며 쉘에 로컬 임)
  • 모든 프로세스에 존재하는 환경 변수. 그것들은 보통 fork()및에 보존 exec()되므로 자식 프로세스는 상속합니다.

다음을 사용하여 명령을 호출 할 때 :

  A=foo B=bar command

코맨드 (환경) 변수 환경 내에서 실행 A로 설정 foo하고 B로 설정한다 bar. 그러나이 명령 행을 사용하면 현재 쉘 변수 A변경되지 않은 상태B 로 남습니다 .

이것은 다음과 다릅니다.

A=foo; B=bar; command

여기에, 쉘 변수 AB정의와 명령은 환경 변수없이 실행 AB정의. 의 값 AB에서 액세스 할 수 없습니다 command.

그러나 일부 쉘 변수가 export-ed 인 경우 해당 환경 변수는 해당 쉘 변수와 동기화됩니다. 예:

export A
export B
A=foo; B=bar; command

이 코드와 함께, 양 변수와 쉘 환경 변수로 설정 foo하고 bar. 환경 변수는 하위 프로세스에 의해 상속되므로 command해당 값에 액세스 할 수 있습니다.

원래 질문으로 돌아가려면 다음을 수행하십시오.

IFS='a' read

read영향을받습니다. 실제로이 경우 변수 read값에 신경 쓰지 않습니다 IFS. IFS다음과 같이 행을 분할하고 여러 변수에 저장하도록 요청할 때만 사용 합니다.

echo "a :  b :    c" | IFS=":" read i j k; \
    printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"

IFSread인수와 함께 호출하지 않으면 사용되지 않습니다 . ( 편집 : 이것은 사실이 아닙니다 : 공백과 탭과 같은 공백 문자 IFS는 입력 줄의 시작 / 끝에서 항상 무시됩니다.)


대단한 설명입니다! 너무 간단합니다! 나는 몇 달 동안 '세미콜론 없음' 구문에 매료되었습니다 . 그것은 ..! 단순히 로컬 변수를 의미 그것의 경우입니다 rozcietrzewiacz이 날 (큰 시간)의 경로를 열어 다른 질문 ... 그리고 그냥 케이크에 장식을 넣어 가지고 ... 내가 봤는데 이 밤새도록 밤새도록, 그것은 분명하고 좋은 대답을 위해 그만한 가치가 있습니다! .. 감사합니다.
Peter.O

음. 필자는 편집 주석을 여러 번 읽어야했습니다 $IFS. 입력 줄의 시작 / 끝에서 공백 문자 가 제거 되었다고 가정합니다. (어떻게 작동하는지)
zrajm

: 이것 좀 봐 주시기 바랍니다 unix.stackexchange.com/questions/382963/...

쉘은 여전히 ​​입력에서 단어 분할을 수행하기 때문에 단일 변수를 읽을 때도 IFS의 값 중요합니다. 예를 들어, 문자 a<tab>b를 입력하면 read varvar에 값이 생기지 a<space>b만 대신 IFS='<newline>' read var값이 있으면 var의 값이됩니다 a<tab>b.
John Hascall

8

간단히 말해 , 구문이 예제 1 에서 가시적 영향을 미치려면 한 번에 둘 이상의 변수를 읽어야합니다 .IFS=<something> read ...

read예제에서 범위가 누락 되었습니다. 없습니다 에는 테스트 케이스의 루프 내부 IFS의 수정. 두 번째 IFS가 각 라인에서 어떤 영향을 미치는지 정확히 알려 드리겠습니다.

 IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b   read; do echo ...
                                                      ^      ^
                                                      |      |
                                          from here --'       `- to here :)

쉘에서 실행되는 모든 프로그램과 같습니다. 명령 줄에서 정의한 변수는 프로그램 실행에 영향을줍니다. 그리고 당신 만이 (내보내기 때문에). 따라서 IFS이러한 행에서 재정의 를 사용 read하려면 둘 이상의 변수에 값을 지정 하도록 요청 해야합니다 . 다음 예제를 살펴보십시오.

 $ data="a  b   c"
 $ echo "$data" | while           read A B C; do echo \|$A\|$B\|\|$C\|; done
 |a|b||c|
 $ echo "$data" | while IFS=      read A B C; do echo \|$A\|$B\|\|$C\|; done
 |a b c||||
 $ echo "$data" | while IFS='a'   read A B C; do echo \|$A\|$B\|\|$C\|; done
 || b c|||
 $ echo "$data" | while IFS='ab'  read A B C; do echo \|$A\|$B\|\|$C\|; done
 || || c|

1 Gilles에서 방금 배운 것처럼 IFS=''한 필드 만 읽을 때 실제로 공백 을 설정하면 이점이있을 수 있습니다 . 줄의 시작 부분에서 공백이 잘리지 않도록합니다.


좋아 .. 고마워 ... 이번에 받았어 .. 그리고 나는 스케치를 좋아한다 :)
Peter.O

좋아, 이제 다른 질문에서 해당 문제에 대한 내 대답을 보지 못했다는 귀하의 의견을 읽었습니다. 아마 하나의 일반적인 문제이기 때문에 다른 것을 되돌리고 삭제할 수 있습니까?
rozcietrzewiacz

그렇습니다. 두 질문에는 관련된 주제가 있지만 다른 질문의 제목은 "왜 IFS= readIFS 환경 변수를 재설정하기 위해 선호 하는가? "입니다. 그러므로 지역 변수는 명령 호출자가 설정할 수 있다는 것을 알지 못했습니다. 그것은 그 질문에 대한 답이었습니다. 이 질문의 요점을 해결하기 위해 더 발전했지만, 나는 이미이 질문을했다는 것을 깨달았을 것입니다. 아마도 두 질문은 두 질문과 비슷 sed하기 때문에 그대로 유지하려는 느낌은 ... 구글에 구글에 대한 더 많은 제목 .
Peter.O
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.