쉘 스크립트에서는 명령줄의 출력을 한 줄씩 구문 분석해야 합니다. 출력에는 빈 줄이 포함될 수 있으며 이는 관련이 있습니다. 나는 bash가 아닌 ash를 사용하고 있으므로 프로세스 대체에 의지할 수 없습니다. 나는 이것을 시도하고 있습니다 :
OUT=`my_command`
IFS=$'\n'
i=1
for line in $OUT; do
echo $line
eval VAL$i=$line
i=$((i+1))
done
그러나 이는 $OUT에서 빈 줄을 삭제합니다. 빈 줄도 처리되도록 하려면 어떻게 해야 합니까?
답변1
작동하는 쉘 루프는 다음과 같습니다.
set -f -- "-$-"' -- "$@" '"
${IFS+IFS=\$2} ${out+out=\$3}" \
"$IFS" "$out" "$@"
IFS='
';for out in $(my command|grep -n '.\|')
do : something with "${out%%:*}" and "${out#*:}"
done
unset IFS out
eval "set +f $1"
shift 3
빈 줄이 없도록 정렬하면 됩니다. 처음에는 이 목적으로 제안했지만 nl
다시 생각해보면 nl
논리적 페이지 구분 기호가 입력에 나타나서 출력이 왜곡될 수 있습니다.(실제로는 빈 행으로 끝나고 번호가 매겨진 행에 영향을 미칩니다. 하지만 다른 목적으로는 매우 편리한 기능입니다.). 밖의아니요논리적인 페이지 나누기를 해석하면 grep -n '.\|'
결과는 동일합니다.
이와 같은 파이프라인과 일부 매개변수 대체를 사용하면 빈 줄 문제를 피할 수 있을 뿐만 아니라 각 반복에 동시에 번호가 미리 지정됩니다.(현재 반복 횟수는 이제 사용자에게 제공된 각 값의 시작 부분에 있으며 $out
그 뒤에는 :
).
이 set ... IFS=...
줄의 목적은 쉘의 상태가 변경 전의 위치로 복원되도록 하는 것입니다. 함수가 아닌 스크립트인 경우 이러한 예방 조치는 과잉일 수 있습니다. 그래도 해야 해적어도 set -f
쉘 분할 전에 의도하지 않은 입력 오류를 피하십시오.
그러나 프로세스 대체에 (d)ash
대해서는<(
)
그런 다음 다시 데비안에서( dash
)파생됨ash
(예를 들어 busybox ash
)파일 설명자 연결 처리와 여기에 있는 문서가 익숙할 수 있는 프로세스 대체에 대한 <(
더 나은 대안을 제공한다는 것을 알 수 있습니다 )
.
다음 예를 고려하십시오.
exec "$((i=3))"<<R "$((o=4))"<<W 3<>/dev/fd/3 4<>/dev/fd/4
R
W
sed -u 's/.*/here I am./' <&"$o" >&"$i" &
echo "hey...sed?" >&"$o"
head -n1 <&"$i"
왜냐면 파생 상품이 여기에 있기 때문입니다 dash
. 대신 익명 파이프를 사용한 문서입니다.(대부분의 다른 껍질과 마찬가지로)일반 파일과 함께 사용하고 /dev/fd/[num]
Linux 시스템에서의 링크는 파일 설명자의 백업 파일을 참조하는 간접적인 방법을 제공하기 때문입니다.(파일 시스템에서 참조할 수 없는 경우에도 - 예: 익명 파이프)위의 순서는 호출될 수 있는 일부 쉘을 설정하는 매우 간단한 방법을 보여줍니다.공동 프로세스. 예를 들어 Linux 시스템에서 busybox ash
또는 Linux 시스템에서dash
(다른 사람에 대해서는 보증하지 않습니다)위 내용은 다음과 같이 인쇄됩니다.
here I am.
$i
...그리고 쉘이 파일 설명자를 닫을 때까지 계속 그렇게 할 것입니다 $o
. 버퍼링 문제를 피하기 위해 -u
GNU 에서 제공하는 nbuffered 스위치를 사용 하지만, 스위치가 없어도 필요한 경우 백그라운드 프로세스에 대한 입력을 필터링하고 sed
파이프의 바이트 단위로 시간을 측정할 수 있습니다.conv=sync
\0NUL
dd
sed
대화형 셸에서 위의 내용을 일반적으로 사용하는 방법은 다음과 같습니다.
: & SEDD=$$$!
sed -un "/^$SEDD$/!H;//!d;s///;x;/\n/!q;s///;s/%/&&/g;l" <&"$o" >&"$i" &
...그 배경 a는 sed
고유한 구분 기호가 나타날 때까지 입력을 읽고 저장합니다. 이 시점에서 이전 버퍼 %
에 있던 내용을 두 배로 늘리고 H
익명 파이프 exec
형식 친화적인 C에서 단일 문자열의 정의 문자열로 printf를 인쇄합니다. line - 또는 결과가 80자를 초과하는 경우 여러 줄에 표시됩니다. 마지막 항목(GNU의 경우 sed
)은 w/ 로 처리할 수 있습니다. 이 스위치는 절대로 줄 바꿈을 하지 않도록 sed -l0
지시하는 스위치입니다 . 또는 다음과 같습니다.sed
\
fmt=
while IFS= read -r r <&"$i"
case $r in (*$)
! fmt=$fmt$r ;;esac
do fmt=$fmt${r%?}
done
어쨌든, 나는 다음과 같이 버퍼를 구축했습니다.
echo something at sed >&"$o"
printf '%s\n' more '\lines%' at sed "$SEDD" >&"$o"
그리고 그것을 잡아당기면 다음과 같습니다...
IFS= read -r fmt <&"$i"
다음에 일어나는 일은 다음 과 같습니다 $fmt
.
printf %s\\n "$fmt"
something at sed\nmore\n\\lines%%\nat\nsed$
sed
인쇄할 수 없는 문자에 대한 C 스타일 8진수 이스케이프도 수행됩니다.
그래서 나는 그것을 다음과 같이 사용할 수 있습니다 ...
printf "%d\n${fmt%$}\n" 1 2 3
...인쇄...
1
something at sed
more
\lines%
at
sed
2
something at sed
more
\lines%
at
sed
3
something at sed
more
\lines%
at
sed
sed
예를 들어 필요에 따라 파이프를 종료하고 해제 할 수 있습니다 .
printf %s\\n "$SEDD" "$SEDD" >&"$o"
exec "$i">&- "$o">&-
fd를 한 번만 사용하는 대신 fd를 보유하면 이런 종류의 작업을 수행할 수 있습니다. 필요한 만큼 백파이프를 유지 관리할 수 있으며, 커널이 해당 링크를 소유한 프로세스를 제외한 어떤 프로세스에도 이러한 링크를 제공하지 않기 때문에 명명된 파이프보다 더 안전합니다.(당신의 껍질), 명명된 파이프는 찾을 수 있지만(도청/도둑질도 포함)참조된 파일에 액세스할 수 있는 모든 프로세스는 파일 시스템에서 이 작업을 수행할 수 있습니다.
프로세스 교체를 수행하는 쉘에서 비슷한 작업을 수행하려면 아마도 다음과 같이 할 수 있습니다.
eval "exec [num]<>"<(:)
...하지만 시도해 본 적은 없습니다.
답변2
이 방법:
i=1
my_command | while read line; do
echo $line
eval VAL$i="$line"
i=$((i+1))
done
명령의 출력은 한 줄씩 읽히므로 먼저 변수에 저장할 필요 없이 줄(빈 줄 포함)이 개별적으로 처리됩니다. 출력이 메모리에 두 번 저장되지 않고 bash 스크립트는 명령이 완료된 직후가 아니라 출력 직후에 줄 처리를 시작할 수 있으므로 메모리도 절약됩니다.
편집: VALx 변수는 위의 하위 셸에 설정되어 있으므로 수정해야 합니다.
eval `i=1
my_command | while read line; do
# echo $line
echo "VAL$i=\"$line\""
i=$((i+1))
done`
정말로 필요한 경우에도 echo $line
몇 가지 수정이 필요합니다.
답변3
여기 문서를 사용하여 이를 구현했습니다.
i=1
while read -r line; do
eval VAL$i=\$line
i=$((i+1))
done <<EOF
$(my_command)
EOF
좋은 결과.
업데이트됨: Gilles 및 mikeserv의 피드백이 통합되었습니다.