새 줄과 bash 변수

새 줄과 bash 변수

텍스트 파일(또는 파이프로 연결된 출력, 여기서는 중요하지 않음)이 있습니다.

memcached.uptime 1061374
memcached.curr_connections 480
memcached.cmd_get 478962548
memcached.cmd_set 17641364
memcached.cmd_flush 0

이 명령을 사용하면 cat test.txt | while read i; do echo $i; done상당히 예상되는 출력이 생성됩니다.

memcached.uptime 1061374
memcached.curr_connections 480
memcached.cmd_get 478962548
etc

하지만 반복하면 for i in $(cat test.txt); do echo $i; done다른 내용이 표시됩니다.

memcached.uptime
1061374
memcached.curr_connections
480
memcached.cmd_get
478962548
etc

문제는: 왜? ? ?

답변1

존재하다:

cat test.txt | while read i; do echo $i; done

당신은 꽤 많은 쉘 스크립팅 나쁜 습관을 벼락치기로 만들었습니다.

먼저 언급해야 하지만쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?.

예를 들어 다음을 입력해 보세요.

-n
/*/*/*/../../../*/*/*
  foo\
bar

쉘 루프를 꼭 사용해야 한다면 아마도 다음과 같아야 할 것입니다:

{
while IFS= read <&3 -r i; do
  printf '%s\n' "$i" || exit
done
[ -z "$i" ] || printf %s "$i" || exit
} 3< test.txt

존재하다

for i in $(cat test.txt); do echo $i; done

이는 또 다른 나쁜 습관으로 대체될 수 있습니다. 여기에 인용하지 않은 타당한 이유가 있습니다 $(cat test.txt). 분할+글로브 연산자의 분할 부분을 원하지만 분할할 항목을 지정하고 글로브 부분을 비활성화하는 것을 잊어버렸습니다.

IFS='
' # split on newline only. The default value of $IFS
  # contains space, tab and newline which explains why you see
  # one word per line
set -o noglob # disable glob
for i in $(cat test.txt); do
  printf '%s\n' "$i" || exit
done

루프를 시작하기 전에 빈 줄은 여전히 ​​건너뛰고 파일 내용을 읽고 메모리에 저장합니다(여러 번).

답변2

대답은 $(command)명령의 원시 출력으로 확장하는 것입니다. 그러면 쉘이 이에 대해 일반적인 단어 분할을 수행합니다. 분리에는 다음이 포함됩니다.어느공백은 단어 구분 기호로 처리됩니다.

또한 텍스트를 구문 분석하는 중 하나에서 두 가지 다른 작업을 수행하고 있습니다 read.철사없이 입력단어$(cat)입력이고 다른 하나는 루프에서 출력을 반복하는 것입니다 for. 비슷한 결과를 얻을 수도 있습니다 IFS='\n' for i in $(cat test.txt); do echo "$i"; done.

관련 정보