여러 줄 문자열을 한 줄씩 반복합니다.

여러 줄 문자열을 한 줄씩 반복합니다.

/bin/shBSD 플랫폼의 POSIX 쉘()에서 여러 줄 문자열을 처리하고 한 줄씩 반복하고 싶습니다. Bash는 기본 BSD 배포판에 포함되어 있지 않으며 GPL에 따라 라이센스가 부여되어 있으므로 일반적으로 사용할 수 있도록 노력하고 있습니다 /bin/sh.

파이프를 사용하여 솔루션을 찾았지만 일반 /bin/sh셸에서는 이러한 솔루션이 별도의 프로세스로 처리되므로 다음이 작동하지 않습니다.

MULTILINE="`cat ${SOMEFILE}`"
SOMEVAR="original value"

echo "${MULTILINE}" | while IFS= read -r SINGLELINE
do
 SOMEVAR="updated value"
 echo "this is a single line: ${SINGLELINE}"
 echo "SOMEVAR is now: ${SOMEVAR}"
done

echo "Final SOMEVAR is unchanged: ${SOMEVAR}"

${SOMEVAR}위의 예에서는 변수 변경(즉, while 루프 외부에서 액세스할 수 없음)을 제외하고 내가 원하는 작업을 수행합니다.

내 질문: 이 제한 없이 비슷한 작업을 어떻게 수행할 수 있습니까? 많은 솔루션에는 Bash가 필요하지만 저는 표준 POSIX-shell을 사용하고 있습니다 /bin/sh.

답변1

여기에서 설명서를 사용할 수 있습니다.

while IFS= read -r SINGLELINE
do
  SOMEVAR="updated value"
  printf '%s\n' "this is a single line: ${SINGLELINE}"
  printf '%s\n' "SOMEVAR is now: ${SOMEVAR}"
done << EOF
$MULTILINE
EOF
printf '%s\n' "Final SOMEVAL is still $SOMEVAR"

sh구현 에 따라 여기 문서는 삭제된 임시 파일(쉘이 변수의 확장과 개행 문자를 미리 저장함) 또는 쉘이 변수의 확장과 그 뒤에 오는 파이프를 제공하는 파이프로 구현됩니다. 개행. 두 경우 모두 리디렉션된 명령은 원래 Bourne 셸(현재는 더 이상 사용되지 않으며 POSIX 호환 셸이 아님) 이외의 하위 셸(POSIX에서 요구하는 대로)에서 실행되지 않습니다.

또는 분할+glob을 사용할 수 있습니다.

IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
  SOMEVAR="updated value"
  printf '%s\n' "this is a single line: ${SINGLELINE}"
  printf '%s\n' "SOMEVAR is now: ${SOMEVAR}"
done
printf '%s\n' "Final SOMEVAL is still $SOMEVAR"

그러나 빈 줄은 건너뜁니다.

답변2

파이프 없이 파일에서 직접 읽을 수 있습니다. 이렇게 하면 서브셸에서 루프가 실행되는 것을 방지하므로 while루프 후에 변경된 값을 볼 수 있습니다 .$SOMEVALUE

SOMEVAR="original value"

while IFS= read -r SINGLELINE
do
    SOMEVAR="updated value"
    printf 'this is a single line: %s\n' "$SINGLELINE"
    printf 'SOMEVAR is now: %s\n' "$SOMEVAR"
done <"$SOMEFILE"

printf 'Final SOMEVAR is: %s\n' "$SOMEVAR"

변수 사용을 고집한다면 $MULTILINE파일에 쓰고 거기에서 읽으십시오.

tmpfile=$(mktemp)
printf '%s\n' "$MULTILINE" >"$tmpfile"

while ...; do
   ...
done <"$tmpfile"
rm "$tmpfile"

또한 관련:

$SOMEVAR위에 링크된 질문에 대한 답변에서는 모든 사용이 파이프 끝의 하위 쉘에서 발생하는 방식으로 프로그램을 작성하는 것이 좋습니다 .

MULTILINE=$(cat "$SOMEFILE")
SOMEVAR="original value"

printf '%s\n' "$MULTILINE" | {
    while IFS= read -r SINGLELINE
    do
        SOMEVAR="updated value"
        printf 'this is a single line: %s\n' "$SINGLELINE"
        printf 'SOMEVAR is now: %s\n' "$SOMEVAR"
    done

    printf 'Final SOMEVAR is: %s\n' "$SOMEVAR"
}

또한 관련될 수 있습니다:

관심을 가질 수 있는 기타 질문:

답변3

이것은 나에게 효과적입니다.

$ cat bin/test
#! /bin/sh
SOMEFILE=$1
MULTILINE="`cat ${SOMEFILE}`"
SOMEVAR="blah"

echo "${MULTILINE}" | while IFS= read -r SINGLELINE
do
 echo "this is a single line: ${SINGLELINE}"
 echo "but accessing this var fails: ${SOMEVAR}"
done

그리고

$ bin/test bin/test
this is a single line: #! /bin/sh
but accessing this var fails: blah
this is a single line: SOMEFILE=$1
but accessing this var fails: blah
this is a single line: MULTILINE="`cat ${SOMEFILE}`"
but accessing this var fails: blah
this is a single line: SOMEVAR="blah"
but accessing this var fails: blah
this is a single line:
but accessing this var fails: blah
this is a single line: echo "${MULTILINE}" | while IFS= read -r SINGLELINE
but accessing this var fails: blah
this is a single line: do
but accessing this var fails: blah
this is a single line:  echo "this is a single line: ${SINGLELINE}"
but accessing this var fails: blah
this is a single line:  echo "but accessing this var fails: ${SOMEVAR}"
but accessing this var fails: blah
this is a single line: done
but accessing this var fails: blah

관련 정보