2017-10-12 133 views
8

Với bash 4.1.2 và 4.3.48, kịch bản sau đây cung cấp cho các đầu ra mong đợi:"printf -v" bên trong chức năng không làm việc với sản lượng chuyển hướng

#!/bin/bash 

returnSimple() { 
    local __resultvar=$1 
    printf -v "$__resultvar" '%s' "ERROR" 
    echo "Hello World" 
} 

returnSimple theResult 
echo ${theResult} 
echo Done. 

Output như mong đợi:

$ ./returnSimple 
Hello World 
ERROR 
Done. 

Tuy nhiên, khi stdout từ chức năng được chuyển đến một quy trình khác, việc gán biến số __resultvar không hoạt động nữa:

#!/bin/bash 

returnSimple() { 
    local __resultvar=$1 
    printf -v "$__resultvar" '%s' "ERROR" 
    echo "Hello World" 
} 

returnSimple theResult | cat 
echo ${theResult} 
echo Done. 

Output mong đợi:

$ ./returnSimple 
Hello World 

Done. 

Tại sao printf -v không làm việc trong trường hợp thứ hai? Nếu printf -v không ghi giá trị vào biến kết quả độc lập liệu đầu ra của hàm có được dẫn tới một quá trình khác không?

+0

Đường ống khác với chuyển hướng IO. – chepner

+0

@chepner Đúng, và đó cũng là lý do tại sao tôi quan sát thấy trường hợp sử dụng này hoạt động với chuyển hướng, nhưng không phải với đường ống ... đã cố định chi tiết đó trong câu hỏi –

Trả lời

8

Xem man bash, phần trên Pipelines:

Mỗi lệnh trong một đường ống được thực hiện như một quá trình riêng biệt (ví dụ, trong một subshell).

Đó là lý do tại sao khi bạn viết cmd | cat, cmd nhận bản sao của biến mà nó không thể sửa đổi.

Một bản demo đơn giản:

$ test() ((a++)) 
$ echo $a 

$ test 
$ echo $a 
1 
$ test | cat 
$ echo $a 
1 
+1

Cảm ơn, đó chính xác là những gì tôi đã bỏ lỡ ... Tôi chỉ cũng thấy rằng ;-) –

2

Điều thú vị đủ, tương tự cũng xảy ra khi sử dụng eval $__resultvar="'ERROR'" thay vì báo cáo kết quả printf -v. Do đó, đây không phải là vấn đề liên quan đến printf. Thay vào đó, hãy thêm echo $BASH_SUBSHELL vào cả tập lệnh chính và hàm cho biết rằng trình vỏ sẽ sinh ra một vỏ con trong trường hợp thứ hai - vì nó cần đưa đầu ra từ hàm này sang một tiến trình khác. Do đó các chức năng chạy trong một vỏ phụ:

#!/bin/bash 

returnSimple() { 
    local __resultvar=$1 
    echo "Sub shell level: $BASH_SUBSHELL" 
    printf -v "$__resultvar" '%s' "ERROR" 
} 

echo "Sub shell level: $BASH_SUBSHELL" 
returnSimple theResult | cat 
echo ${theResult} 
echo Done. 

Output:

% ./returnSimple.sh 
Sub shell level: 0 
Sub shell level: 1 

Done. 

Đây là lý do tại sao bất kỳ bài tập biến từ bên trong chức năng không được truyền lại cho kịch bản gọi điện thoại.

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