2009-03-05 39 views
418

Tôi đã có một kịch bản 'myscript' mà kết quả đầu ra như sau:Chụp đầu ra dòng nhiều vào một biến Bash

abc 
def 
ghi 

trong kịch bản khác, tôi gọi:

declare RESULT=$(./myscript) 

$RESULT nhận được giá trị

abc def ghi 

Có cách nào để lưu kết quả bằng ký tự mới hay với ký tự '\ n' để tôi c đầu ra nó với 'echo -e'?

+1

nó làm tôi ngạc nhiên. bạn không có $ (cat ./myscipt)? nếu không tôi đã có thể mong đợi nó để cố gắng thực hiện lệnh abc, def và ghi –

+0

@ litb: có, tôi cho rằng như vậy; bạn cũng có thể sử dụng $ (<./ myscript) để tránh thực thi lệnh. –

+2

(NB: hai chú thích ở trên đề cập đến một sửa đổi của câu hỏi bắt đầu _Tôi đã có một kịch bản 'myscript' có chứa sau đây, dẫn đến các câu hỏi. 'myscript' mà kết quả đầu ra sau đây) làm cho các bình luận không cần thiết. Tuy nhiên, bản sửa đổi là từ 2011-11-11, lâu sau khi hai ý kiến ​​được thực hiện –

Trả lời

784

Trên thực tế, kết quả chứa những gì bạn muốn - để chứng minh:

echo "$RESULT" 

Những gì bạn thấy là những gì bạn nhận được từ:

echo $RESULT 

Như đã đề cập trong các ý kiến, sự khác biệt là (1) phiên bản được trích dẫn kép của biến (echo "$RESULT") bảo tồn khoảng cách nội bộ của giá trị chính xác như được biểu diễn trong biến - dòng mới, tab, nhiều khoảng trắng và tất cả - ở đó s (2) phiên bản chưa được kiểm duyệt (echo $RESULT) thay thế mỗi chuỗi của một hoặc nhiều khoảng trống, tab và dòng mới bằng một dấu cách. Do đó (1) bảo toàn hình dạng của biến đầu vào, trong khi (2) tạo ra một dòng đầu ra có khả năng rất dài với 'các từ' được phân cách bằng dấu cách đơn (trong đó 'từ' là một chuỗi ký tự không khoảng trắng; không có bất kỳ chữ số trong bất kỳ từ nào).

+59

@troelskn: sự khác biệt là (1) phiên bản được trích dẫn kép của biến duy trì khoảng cách bên trong của giá trị chính xác như được biểu diễn trong biến, dòng mới, tab, nhiều khoảng trống và tất cả, trong khi (2) phiên bản không được kiểm soát thay thế mỗi chuỗi của một hoặc nhiều khoảng trắng, tab và dòng mới bằng một dấu cách. Do đó (1) bảo toàn hình dạng của biến đầu vào, trong khi (2) tạo ra một dòng đầu ra có khả năng rất dài với 'các từ' được phân cách bằng dấu cách đơn (trong đó 'từ' là một chuỗi ký tự không khoảng trắng; không có bất kỳ chữ và số trong bất kỳ từ nào). –

+17

Để làm cho câu trả lời dễ hiểu hơn: câu trả lời cho biết rằng "$ RESULT" giữ lại dòng mới, trong khi echo $ RESULT thì không. –

+0

Điều này không bảo toàn được dòng mới và không gian hàng đầu trong một số trường hợp. – CommaToast

72

Một lỗ hổng khác với điều này là command substitution - $() - dải đường kẻ mới. Có lẽ không phải lúc nào quan trọng, nhưng nếu bạn thực sự muốn giữ là chính xác những gì đầu ra, bạn sẽ phải sử dụng một dòng khác và một số trích dẫn:

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

Điều này đặc biệt quan trọng nếu bạn muốn handle all possible filenames (để tránh hành vi không xác định như hoạt động trên tệp sai).

+3

+1 Điều này đúng và những gì còn thiếu trong câu trả lời của JonathanLeffler! –

+3

Tôi phải làm việc một thời gian với một vỏ bị hỏng mà không loại bỏ dòng mới cuối cùng từ [lệnh thay thế] (http://www.gnu.org/software/bash/manual/bash.html#Command-Substitution) (nó là _not_ [quá trình thay thế] (http://www.gnu.org/software/bash/manual/bash.html#Process-Substitution)), và nó đã phá vỡ gần như tất cả mọi thứ. Ví dụ, nếu bạn đã làm '' pwd = 'pwd'; ls $ pwd/$ file'', bạn có một dòng mới trước '/', và kèm theo tên trong dấu nháy kép không giúp được gì. Nó đã được sửa chữa nhanh chóng. Điều này đã trở lại trong khung thời gian 1983-5 trên ICL Perq PNX; trình bao không có '$ PWD' làm biến tích hợp. –

0

Làm thế nào về điều này, nó sẽ đọc từng dòng đến một biến và có thể được sử dụng sau đó! nói ra myscript được chuyển hướng đến một tập tin gọi myscript_output

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

Vâng, đó không phải là bash, đó là awk. – vadipp

12

Ngoài các câu trả lời được đưa ra bởi @ l0b0 Tôi chỉ có tình huống mà tôi cần cả hai giữ bất kỳ dòng mới ra trailing bởi kịch bản kiểm tra các mã trả về của tập lệnh. Và vấn đề với câu trả lời của l0b0 là 'echo x' đã đặt lại $? trở về zero ... vì vậy tôi cố gắng đưa ra giải pháp này rất xảo quyệt:

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

Trong trường hợp đó bạn quan tâm đến dòng cụ thể, sử dụng kết quả mảng:

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

Nếu có các khoảng trống trong các dòng, điều này sẽ tính các trường (nội dung giữa các khoảng trắng) thay vì các dòng. – Liam

+3

điều này không hoạt động trên Dash hoặc POSIX Shell – gpanda

+1

Bạn sẽ sử dụng 'readarray' và thay thế tiến trình thay vì lệnh thay thế:' readarray -t RESULT <<(./myscript> '. – chepner

0

Sau cố gắng hầu hết các giải pháp ở đây, điều đơn giản nhất tôi thấy là hiển nhiên - sử dụng một tệp tạm thời. Tôi không chắc chắn những gì bạn muốn làm với đầu ra nhiều dòng của bạn, nhưng sau đó bạn có thể đối phó với nó theo từng dòng bằng cách đọc.Về điều duy nhất bạn có thể không thực sự làm là dễ dàng dính nó tất cả trong cùng một biến, nhưng đối với hầu hết các mục đích thực tế này là cách dễ dàng hơn để đối phó với.

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

nhanh hack để làm cho nó làm những hành động yêu cầu:

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

Chú giải này thêm một dòng thêm. Nếu bạn làm việc trên nó, bạn có thể viết mã xung quanh nó, tôi chỉ là quá lười biếng.


EDIT: Trong khi trường hợp này hoạt động hoàn hảo tốt, mọi người đọc bài viết này nên lưu ý rằng bạn có thể dễ dàng bí stdin của bạn bên trong vòng lặp while, do đó đem lại cho bạn một kịch bản mà sẽ chạy một dòng, stdin rõ ràng, và thoát . Giống như ssh sẽ làm điều đó tôi nghĩ? Gần đây tôi vừa xem, các ví dụ mã khác tại đây: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while

Một lần nữa! Lần này với một filehandle khác (stdin, stdout, stderr là 0-2, vì vậy chúng ta có thể sử dụng & 3 hoặc cao hơn trong bash).

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

bạn cũng có thể sử dụng mktemp, nhưng đây chỉ là ví dụ về mã nhanh. Cách sử dụng cho mktemp trông giống như:

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

Sau đó, sử dụng $ filenamevar giống như tên thật của tệp. Có lẽ không cần phải được giải thích ở đây nhưng ai đó phàn nàn trong các ý kiến.

+0

Tôi đã thử các giải pháp khác nữa, với đề nghị đầu tiên của bạn cuối cùng tôi đã nhận được kịch bản của tôi làm việc –

+1

Downvote: Điều này quá phức tạp và không tránh được nhiều lỗi ['bash' phổ biến] (http://mywiki.wooledge.org/BashPitfalls) . – tripleee

+0

Ya ai đó nói với tôi về vấn đề sthand filehandle lạ ngày khác và tôi đã như "wow". Lemme thêm một cái gì đó thực sự nhanh chóng. – user1279741

Các vấn đề liên quan