저는 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
줄을 읽으려면 셸에 내장된 명령어를 사용하세요.읽다기능,
$읽기 도와주세요 | 머리 -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