줄 바꿈으로 명령 출력을 분할하시겠습니까?

줄 바꿈으로 명령 출력을 분할하시겠습니까?

여러 줄을 반환하는 명령이 있습니다. 추가 처리를 위해서는 이러한 각 행을 처리해야 합니다.

현재 코드는 IFS(내부 필드 구분 기호):

ROWS=$(some command returning multiple lines)

O=$IFS #save original IFS
IFS=$(echo -en "\n\b") # set IFS to linebreak

for ROW in ${ROWS[@]}
do
  echo "$ROW"
done

IFS=$O #restore old IFS

IFS를 수정하지 않고 여러 줄 출력의 한 줄에 액세스하는 더 좋은 방법이 있는지 궁금합니다. 특히 IFS를 수정하면서 스크립트의 가독성이 매우 떨어졌습니다.

업데이트: choroba로부터 다음과 같은 답변을 받는 데 어려움을 겪고 있습니다.

while IFS= read -r line ; do
    let var+=line #line 42
done << $(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")
echo "$var" # line 44

나에게주세요

./bla.sh: row 44: Warning: here-document at line 43 delimited by end-of-file (wanted `$(sqlite3 -list -nullvalue NULL -separator , /var/log/asterisk/master.db ${QUERY})')
./bla.sh: row 42: let: echo "": syntax error: invalid arithmetic operator. (error causing character is \"""\").

누구든지 이 문제를 해결하도록 도와줄 수 있나요? 감사해요!

답변1

루프 read에서는 어떻습니까 ?while

some command returning multiple lines | while IFS= read -r line ; do
    echo "$line"
done

그러나 파이프는 서브셸에서 실행되므로 스크립트의 나머지 부분에서는 변수 값을 변경할 수 없습니다. while 루프에서 살아남기 위해 무언가가 필요한 경우 bash의 프로세스 대체를 사용할 수 있습니다.

while IFS= read -r line ; do
    let var+=line
done < <(some command returning multiple lines)
echo "$var"

답변2

IFS개행 문자를 설정하는 것만으로는 충분하지 않습니다. (그런데 왜 백스페이스 문자로 나누는 걸까요?)

코드에서 ${ROWS[@]}(이상한 작성 방법입니다 $ROWS. ROWS배열이 아닙니다.) 큰 따옴표로 묶이지 않습니다. (큰따옴표 안에 있으면 ROWS배열이 아니기 때문에 문자열을 얻게 됩니다.) 따라서 쉘은 변수의 값을 IFS각 문자에 대한 필드로 분할한 다음 각 필드를 전역 패턴으로 처리합니다. 예를 들어, 명령으로 인쇄된 줄 중 하나에 단일 문자가 포함되어 있으면 *해당 문자는 현재 디렉터리의 파일 이름으로 대체됩니다.

닫는 와일드카드를 사용할 수 있습니다 set -f. 대부분의 경우 셸을 사용하는 필드 분할 기능을 설정할 때 IFS와일드카드도 꺼야 합니다. 다시 켜는 데 사용합니다 set +f.

명령 출력을 한 줄씩 읽는 신뢰할 수 있는 관용구는 다음과 같습니다.while IFS= read -r.

some command returning multiple lines |
while IFS= read -r ROW; do
done

대부분의 셸은 별도의 하위 셸에서 파이프라인의 각 명령을 실행합니다. 따라서 변수를 설정하고 루프 후에 이를 사용해야 하는 경우 루프와 함께 이러한 명령을 그룹으로 묶습니다. (부모 셸에서 파이프라인의 마지막 명령을 실행하는 Ksh 및 zsh는 예외입니다.)

some command returning multiple lines | {
  while IFS= read -r ROW; do
    row_count=$((row_count+1))
  done
  echo "There were $row_count rows."
}

답변3

업데이트된 질문에서 여기에 문서와 문자열 구문을 혼합했습니다.

또는 여기 문서를 사용하세요.

while IFS= read -r line ; do
    let var+=line #line 42
done <<ENDMARK
$(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")
ENDMARK

또는 문자열은 다음과 같습니다.

while IFS= read -r line ; do
    let var+=line #line 42
done <<< $(sqlite3 -list -nullvalue NULL -separator ',' /var/log/asterisk/master.db "${QUERY}")

답변4

스크립트의 세부 사항에 따라 간단한 파이프 메커니즘을 사용하여 명령을 연결하면 매우 읽기 쉬운 스크립트가 될 수 있습니다.

이 경우 xargs여러 줄을 분할하여 각 줄에 대해 하나의 명령을 실행할 수 있습니다. 이것은 단지 기본 동작입니다 xargs.

(some command returning multiple lines) | xargs -I{} echo {}

또는 작업 데모로:

$ echo -e "line 1\nline 2" | xargs -I{} echo "next line: {}"

next line: line 1
next line: line 2

관련 정보