줄 바꿈뿐만 아니라 모든 공백에서 텍스트를 분할하여 명령 출력을 셸의 변수로 읽습니다.

줄 바꿈뿐만 아니라 모든 공백에서 텍스트를 분할하여 명령 출력을 셸의 변수로 읽습니다.

저는 FreeBSD 11에서 sh(bash/csh 아님)를 사용하고 있는데 이것을 이해하지 못합니다:

콘솔에서

주문하다:zpool status -v

결과:

  pool: My_pool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.

스크립트에서 줄별로 분할하고 한 번에 줄을 인쇄합니다.

#!/bin/sh
zp="$(zpool status -v)"
for line in $zp; do
  echo "$line%"
done

결과:

pool:%
My_pool%
state:%
ONLINE%
status:%
One%
or%
more%
devices%
is%
currently%
being%
resilvered.%
The%
pool%
will%
continue%
to%
function,%
possibly%
in%
a%
degraded%
state.%
action:%
Wait%

내가 찾을 수 있는 모든 정보에 따르면 내가 사용하고 있는 구문은 sh에 적합하며 한 번에 한 단어가 아니라 한 번에 한 줄씩 읽어야 합니다.

내가 무엇을 놓치고 있나요?

답변1

나는 당신이 무엇을 발견했는지 혼란스러워요. 사용하는 구문은 개행뿐만 아니라 공백에 대한 sh 및 분할에 대해서도 정확합니다. 이는 널리 문서화되었습니다. 개행 문자에서 분할된다는 것은 대중적인 오해가 아닙니다. (분할된다는 사실을 이해하지 못하는 것은 일반적인 오해입니다.)

더 정확하게 말하면 따옴표가 없는 변수 확장(예: )을 $zp"split+glob" 연산자라고 부르기도 합니다. 그것이 하는 일은:

  1. 변수의 값을 가져옵니다. 그것은 문자열입니다.
  2. 각 필드 구분 기호에서 이 값을 분할합니다. 필드 구분 기호는 IFS기본적으로 변수 값의 구분 기호입니다.공백, 탭 및 줄 바꿈. (이 기본값은 변수가 설정되지 않은 경우에도 사용됩니다.) 결과는 문자열 목록입니다.
  3. 목록의 각 요소를 와일드카드(glob) 패턴으로 처리합니다. 하나 이상의 파일 이름과 일치하는 경우 이 요소는 일치하는 파일 이름 목록으로 대체됩니다. 그렇지 않으면 요소가 유지됩니다.

예를 들어 디렉터리에 foo, 및 이라는 bar파일이 포함된 경우 baz다음 스크립트는 a*, bar및 의 세 줄을 인쇄합니다 baz.

zq='a* b*'
for word in $zq; do echo "$word"; done

줄바꿈에서 문자열을 분할하려면 IFS줄바꿈을 설정하고 와일드카드 확장을 비활성화하면 됩니다.

#!/bin/sh
set -f
IFS='
'
zq=…
for line in $zq; do
done

이는 모든 sh 및 csh 변형에 적용됩니다.

당신은 또한 볼 수 있습니다공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?

답변2

줄을 읽으려면 셸에 내장된 명령을 사용하세요.읽다기능,

$도움말 읽기|Head-2

읽기: 읽기 [-ers] [-u fd] [-t 시간 ​​초과] [-p 프롬프트] [-a 배열] [-n nchars] [-d delim] [이름...]

표준 입력 또는 -u 옵션이 제공되는 경우 파일 설명자 FD에서 행을 읽습니다.

루프에 넣으면 while짜잔, 몇 줄이 나옵니다:

$ wc -l -w ~/.profile 
  24      47 /Users/jklowden/.profile
$ for W in $(cat ~/.profile); do echo $W; done | wc -l 
  47
$ while read L; do echo $L; done < ~/.profile | wc -l 
  24

관련 정보