여러 줄 출력을 Bash 변수로 캡처


583

다음을 출력하는 스크립트 'myscript'가 있습니다.

abc
def
ghi

다른 스크립트에서는 다음과 같이 호출합니다.

declare RESULT=$(./myscript)

그리고 $RESULT가치를 얻는다

abc def ghi

줄 바꿈 또는 '\ n'문자로 결과를 저장하여 ' echo -e'로 출력 할 수있는 방법이 있습니까?


1
놀랍습니다. $ (cat ./myscipt)가 없습니까? 그렇지 않으면 명령 abc, def 및 ghi를 실행하려고 시도했을 것입니다.
Johannes Schaub-litb

@litb : 그렇습니다. 명령 실행을 피하는 $ (<./ myscript)를 사용할 수도 있습니다.
Jonathan Leffler

2
(NB : 위의 두 의견은 시작된 질문의 개정을 나타 냅니다. 다음을 포함하는 'myscript'라는 스크립트가 있는데, 이로 인해 질문 이 생겼습니다 . 질문의 현재 개정 ( 스크립트가 있습니다 ' 다음을 출력하는 myscript ' )는 주석을 불필요하게 만듭니다. 그러나 개정은 두 번의 주석이 작성된 지 얼마되지 않은 2011 년 11 월 11 일 이후입니다.
Jonathan Leffler

답변:


1081

실제로 RESULT에는 다음과 같은 내용이 포함되어 있습니다.

echo "$RESULT"

당신이 보여주는 것은 당신이 얻는 것입니다 :

echo $RESULT

의견에서 언급했듯이, 차이점은 (1) 큰 따옴표로 묶인 변수 버전 ( echo "$RESULT") 은 변수 (줄 바꿈, 탭, 여러 공백 및 모두)에 표시된대로 값의 내부 간격을 유지하지만 (2) ) 따옴표없는 버전 ( echo $RESULT)은 하나 이상의 공백, 탭 및 개행의 각 시퀀스를 단일 공백으로 바꿉니다. 따라서 (1) 입력 변수의 모양을 유지하는 반면 (2) 단일 단어로 구분 된 '단어'를 사용하여 잠재적으로 매우 긴 단일 출력 행을 만듭니다 ( '단어'는 공백 문자가 아닌 일련의 문자입니다. 어떤 단어에서도 영숫자가 될 수 없습니다).


69
@troelskn : 차이점은 (1) 큰 따옴표로 묶인 버전의 변수는 변수, 줄 바꿈, 탭, 여러 개의 공백 및 모두에 표시된 것처럼 값의 내부 간격을 유지하지만 (2) 따옴표없는 버전은 단일 공백이있는 하나 이상의 공백, 탭 및 개행 문자의 각 시퀀스. 따라서 (1) 입력 변수의 모양을 유지하는 반면 (2) 단일 단어로 구분 된 '단어'를 사용하여 잠재적으로 매우 긴 단일 출력 행을 만듭니다 ( '단어'는 공백 문자가 아닌 일련의 문자입니다. 어떤 단어에서도 영숫자가 될 수 없습니다).
Jonathan Leffler

23
답변을보다 쉽게 ​​이해하기 위해 : 답변은 echo "$ RESULT"는 개행을 유지하지만 echo $ RESULT는 그렇지 않다고 알려줍니다.
Yu Shen

일부 상황에서는 줄 바꿈과 선행 공백을 유지하지 못합니다.
CommaToast

3
@CommaToast : 그것에 대해 자세히 설명 하시겠습니까? 후행 줄 바꿈이 손실됩니다. 그 주위에 쉬운 방법이 없습니다. 선행 공백-분실 된 상황에 대해 잘 모르겠습니다.
Jonathan Leffler


90

이것의 또 다른 함정은 명령 대체$()— 마지막 줄 바꿈을 제거 한다는 것 입니다. 당신이 정말로 유지하려면 아마 항상 중요하지만 정확하게 출력 무엇인지, 다른 라인과 일부 인용을 사용해야합니다 :

RESULTX="$(./myscript; echo x)"
RESULT="${RESULTX%x}"

파일 이름 을 잘못 처리 하는 등 정의되지 않은 동작을 피하기 위해 가능한 모든 파일 이름처리 하려는 경우 특히 중요합니다 .


4
나는에서 마지막 개행 제거하지 않은 깨진 쉘 잠시 동안 일해야했다 명령 치환을 (그것이 하지 프로세스 대체 ), 그리고 거의 모든 끊었다. 예를 들어,을 수행 한 경우 pwd=`pwd`; ls $pwd/$file앞에 개행 문자가 있고 /이름을 큰 따옴표로 묶는 것이 도움이되지 않았습니다. 그것은 빨리 고쳐졌다. 이것은 ICL Perq PNX에서 1983-5 년 기간으로 돌아 왔습니다. 쉘 $PWD에는 내장 변수 가 없었습니다 .
Jonathan Leffler

19

특정 행에 관심이있는 경우 결과 배열을 사용하십시오.

declare RESULT=($(./myscript))  # (..) = array
echo "First line: ${RESULT[0]}"
echo "Second line: ${RESULT[1]}"
echo "N-th line: ${RESULT[N]}"

3
행에 공백이 있으면 행이 아닌 필드 (공백 사이의 내용)를 계산합니다.
Liam

2
readarray명령 대체 대신 대체를 사용 하고 처리 readarray -t RESULT < <(./myscript>합니다..
chepner

15

에 의해 주어진 대답에 추가 @ l0b0 나는 단지 내가 모두 필요한 상황이 스크립트에 의해 후행 뉴 라인 출력을 유지했다 스크립트의 리턴 코드를 확인하십시오. 그리고 l0b0의 대답의 문제는 'echo x'가 $를 재설정하고 있다는 것입니다. 다시 제로로 돌아가서 ...이 교활한 해결책을 생각해 냈습니다.

RESULTX="$(./myscript; echo x$?)"
RETURNCODE=${RESULTX##*x}
RESULT="${RESULTX%x*}"

이것은 사랑 스럽습니다. 실제로 die ()종료 코드와 선택적으로 메시지를 받아들이는 함수 를 갖고 싶고 메시지 usage ()를 제공 하기 위해 다른 함수를 사용하고 싶었지만 개행은 계속 뭉개졌습니다. 그 문제를 해결하십시오.
dragon788

1

여기에서 대부분의 솔루션을 시도한 후에 가장 쉬운 것은 임시 파일을 사용하는 것이 분명했습니다. 여러 줄 출력으로 무엇을하고 싶은지 잘 모르겠지만 read를 사용하여 한 줄씩 처리 할 수 ​​있습니다. 실제로 할 수없는 유일한 일은 동일한 변수에 쉽게 넣을 수 있지만 대부분의 실제 목적을 위해 이것은 다루기가 더 쉽습니다.

./myscript.sh > /tmp/foo
while read line ; do 
    echo 'whatever you want to do with $line'
done < /tmp/foo

요청 된 작업을 수행하기위한 빠른 해킹 :

result=""
./myscript.sh > /tmp/foo
while read line ; do
  result="$result$line\n"
done < /tmp/foo
echo -e $result

이것은 여분의 줄을 추가합니다. 작업하면 코드를 작성할 수 있습니다. 너무 게으르다.


편집 :이 사례는 완벽하게 작동하지만 이것을 읽는 사람들은 while 루프 내에서 stdin을 쉽게 스쿼시 할 수 있으므로 한 줄을 실행하고 stdin을 지우고 종료하는 스크립트를 제공합니다. ssh처럼 내가 생각하는 것입니까? 방금 최근에 다른 코드 예제를 보았습니다 : /unix/24260/reading-lines-from-a-file-with-bash-for-vs-while

한번 더! 이번에는 다른 파일 핸들 (stdin, stdout, stderr은 0-2이므로 bash에서 & 3 이상을 사용할 수 있습니다).

result=""
./test>/tmp/foo
while read line  <&3; do
    result="$result$line\n"
done 3</tmp/foo
echo -e $result

mktemp를 사용할 수도 있지만 이것은 간단한 코드 예일뿐입니다. mktemp의 사용법은 다음과 같습니다.

filenamevar=`mktemp /tmp/tempXXXXXX`
./test > $filenamevar

그런 다음 실제 파일 이름처럼 $ filenamevar를 사용하십시오. 아마도 여기에 설명 할 필요는 없지만 누군가 의견에 불평했습니다.


나는 다른 해결책도 시도했다. 첫 번째 제안으로 마침내 스크립트가 작동했다
Kar.ma

1
Downvote :이 방법은 지나치게 복잡하며 여러 가지 일반적인 bash함정 을 피하지 못합니다 .
tripleee 2012 년

나중에 누군가가 이상한 stdin filehandle 문제에 대해 나에게 말했고 나는 "와우"와 같았다. Lemme는 정말 빠르게 무언가를 추가합니다.
user1279741

Bash에서는 read명령 확장자 -u 3를 사용하여 파일 설명자 3을 읽을 수 있습니다.
Jonathan Leffler

안되

0

이것에 대해, 그것은 각 행을 변수로 읽어서 나중에 사용할 수 있습니다! myscript 출력이 myscript_output이라는 파일로 리디렉션된다고 말하십시오.

awk '{while ( (getline var < "myscript_output") >0){print var;} close ("myscript_output");}'

4
글쎄, 그것은 배쉬가 아니다.
vadipp
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.