`while IFS= read..`에서 IFS가 아무런 효과가 없는 이유는 무엇입니까?

`while IFS= read..`에서 IFS가 아무런 효과가 없는 이유는 무엇입니까?

뭔가 완전히 잘못된 것이 있을 수 있지만 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=" "
-----   --  --   --------       -----      ---------   -------                        

답변1

(설명이 길어서 죄송합니다)

예, IFSin 의 변수는 while IFS=" " read; do …나머지 코드에 영향을 주지 않습니다.

먼저 쉘 명령줄에 두 가지 다른 유형의 변수가 있음을 지정합니다.

  • 셸 변수(셸 내에서만 존재하며 셸의 지역 변수임)
  • 모든 프로세스에는 환경 변수가 존재합니다. 이는 일반적으로 저장되므로 fork()하위 exec()프로세스가 이를 상속합니다.

다음을 사용하여 명령을 호출하는 경우:

  A=foo B=bar command

Afoo명령은 (환경) 변수가 로 B설정된 환경에서 실행됩니다 bar. 하지만 이 명령줄을 사용하면 현재 쉘 변수 AB끊임없는.

이는 다음과 다릅니다.

A=foo; B=bar; command

A쉘 변수 및 는 여기에 정의되어 B있으며 명령은 환경 변수 AB정의 없이 실행됩니다. A및 의 값은 B에서 액세스할 수 없습니다 command.

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

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입력 줄의 시작/끝에 있는 공백 문자(예: 공백 및 탭)는 항상 무시됩니다. )

답변2

간단히 말해서,한 번에 여러 변수를 읽어야 합니다.example1IFS=<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 방금 배운대로자일스에서, 하나의 필드만 읽을 때 (공백)로 설정하면 실제로 이점이 있을 수 있습니다 IFS=''. 즉, 줄 시작 부분에서 공백이 잘리는 것을 방지합니다.

관련 정보