답변:
프로세스 대체와 함께 while 루프를 사용할 수 있습니다.
while read -r line
do
echo "$line"
done < <(jobs)
여러 줄 변수를 읽는 가장 좋은 방법은 빈 IFS
변수와 printf
변수를 후행 줄 바꿈으로 설정하는 것입니다.
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
do
echo "$line"
done < <(printf '%s\n' "$var")
참고 : 쉘 체크 sc2031에 따르면 , 서브 쉘을 생성하는 것을 피하기 위해 파이프보다 프로세스 서브 스트 레이션을 사용하는 것이 바람직하다.
또한 변수 jobs
의 이름을 지정하면 일반적인 쉘 명령의 이름이기 때문에 혼동을 일으킬 수 있습니다.
echo
에 printf %s
스크립트가 아닌 순종 입력으로도 작동 할 수 있도록를.
/tmp
은 임시 작업 파일을 만들 수 있기 때문에 항상 디렉토리를 쓸 수 있어야한다는 점에 유의해야 합니다. /tmp
읽기 전용 (및 사용자가 변경할 수 없음) 으로 제한된 시스템 을 사용하는 경우 printf
파이프 와 같은 대체 솔루션을 사용할 가능성에 만족할 것 입니다.
printf "%s\n" "$var" | while IFS= read -r line
한 줄씩 명령 출력을 처리하려면 ( description ) :
jobs |
while IFS= read -r line; do
process "$line"
done
변수에 이미 데이터가있는 경우 :
printf %s "$foo" | …
printf %s "$foo"
는 거의 동일 echo "$foo"
하지만 $foo
문자 그대로 인쇄 하는 반면 echo 명령이로 시작하면 echo 명령에 대한 옵션으로 echo "$foo"
해석 될 수 있으며 일부 쉘에서는 백 슬래시 시퀀스가 확장 될 수 있습니다 .$foo
-
$foo
일부 셸 (ash, bash, pdksh, ksh 또는 zsh는 아님)에서 파이프 라인의 오른쪽은 별도의 프로세스에서 실행되므로 루프에서 설정 한 모든 변수가 손실됩니다. 예를 들어, 다음 줄 계산 스크립트는 이러한 셸에서 0을 인쇄합니다.
n=0
printf %s "$foo" |
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
해결 방법은 나머지 스크립트 (또는 최소한 $n
루프에서 값이 필요한 부분 )를 명령 목록 에 넣는 것입니다 .
n=0
printf %s "$foo" | {
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
}
비어 있지 않은 행에 대한 작업이 충분하고 입력이 크지 않은 경우 단어 분할을 사용할 수 있습니다.
IFS='
'
set -f
for line in $(jobs); do
# process line
done
set +f
unset IFS
설명 : IFS
단일 줄 바꿈으로 설정하면 기본 설정의 공백 문자와 달리 줄 바꿈에서만 단어 분리가 발생합니다. set -f
그렇지 않으면 명령 대체 $(jobs)
또는 변수 substitutino 결과로 발생하는 글 로빙 (예 : 와일드 카드 확장)을 끕니다 $foo
. for
루프의 모든 부분에 작용하는 $(jobs)
명령 출력 모든 비어 있지 않은 선이다. 마지막으로 글 로빙 및 IFS
설정을 복원하십시오 .
local IFS=something
. 전역 범위 값에는 영향을 미치지 않습니다. IIRC unset IFS
는 기본값으로 돌아 가지 않습니다 (그리고 사전에 기본값이 아닌 경우 확실히 작동하지 않습니다).
문제점 : while 루프를 사용하면 서브 쉘에서 실행되고 모든 변수가 손실됩니다. 솔루션 : for 루프 사용
# change delimiter (IFS) to new line.
IFS_BAK=$IFS
IFS=$'\n'
for line in $variableWithSeveralLines; do
echo "$line"
# return IFS back if you need to split new line by spaces:
IFS=$IFS_BAK
IFS_BAK=
lineConvertedToArraySplittedBySpaces=( $line )
echo "{lineConvertedToArraySplittedBySpaces[0]}"
# return IFS back to newline for "for" loop
IFS_BAK=$IFS
IFS=$'\n'
done
# return delimiter to previous value
IFS=$IFS_BAK
IFS_BAK=
while read
bash 에서 루프 로 파이프 하는 것은 while 루프가 서브 쉘에 있음을 의미하므로 변수가 전역 적이 지 않습니다. while read;do ;done <<< "$var"
루프 바디를 서브 쉘이 아닌 것으로 만듭니다. (최근의 bash는 cmd | while
ksh처럼 항상 루프 의 몸체를 서브 쉘 에 넣지 않는 옵션을 가지고 있습니다.)
최근 bash 버전에서 mapfile
또는 readarray
을 사용 하여 명령 출력을 배열로 효율적으로 읽습니다.
$ readarray test < <(ls -ltrR)
$ echo ${#test[@]}
6305
면책 조항 : 끔찍한 예이지만 ls보다 더 나은 명령을 사용할 수 있습니다.
readarray
함수를 넣고 함수를 몇 번 호출합니다.
while IFS= read
... 을 사용하십시오 . 해석을 막으려면read -r