저는 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" 연산자라고 부르기도 합니다. 그것이 하는 일은:
- 변수의 값을 가져옵니다. 그것은 문자열입니다.
- 각 필드 구분 기호에서 이 값을 분할합니다. 필드 구분 기호는
IFS
기본적으로 변수 값의 구분 기호입니다.공백, 탭 및 줄 바꿈. (이 기본값은 변수가 설정되지 않은 경우에도 사용됩니다.) 결과는 문자열 목록입니다. - 목록의 각 요소를 와일드카드(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