Cách chuyển đầu vào vào vòng lặp Bash while và bảo toàn các biến sau khi vòng lặp kết thúc


87

Bash cho phép sử dụng: cat <(echo "$FILECONTENT")

Bash cũng cho phép sử dụng: while read i; do echo $i; done </etc/passwd

để kết hợp hai trước, điều này có thể được sử dụng: echo $FILECONTENT | while read i; do echo $i; done

Vấn đề với cái cuối cùng là nó tạo ra sub-shell và sau khi vòng lặp while kết thúc, biến ikhông thể được truy cập nữa.

Câu hỏi của tôi là:

Làm thế nào để đạt được điều gì đó như thế này: while read i; do echo $i; done <(echo "$FILECONTENT")hay nói cách khác: Làm thế nào tôi có thể chắc chắn rằng ivẫn tồn tại trong vòng lặp while?

Xin lưu ý rằng tôi đã biết về việc thêm câu lệnh while vào {}nhưng điều này không giải quyết được vấn đề (hãy tưởng tượng rằng bạn muốn sử dụng vòng lặp while trong hàm và ibiến trả về )



Liên quan: stackoverflow.com/questions/37229058/… . Giải thích tất cả các tùy chọn bao gồm thay thế quy trình được đề cập bên dưới lastpipevà ưu nhược điểm của chúng.
ivan_pozdeev

Câu trả lời:


115

Ký hiệu chính xác cho Thay thế Quy trình là:

while read i; do echo $i; done < <(echo "$FILECONTENT")

Giá trị cuối cùng của iđược gán trong vòng lặp sẽ khả dụng khi vòng lặp kết thúc. Một thay thế là:

echo $FILECONTENT | 
{
while read i; do echo $i; done
...do other things using $i here...
}

Các dấu ngoặc nhọn là một hoạt động nhóm I / O và bản thân nó không tạo ra một vỏ con. Trong bối cảnh này, chúng là một phần của một đường ống và do đó được chạy dưới dạng một vỏ con, nhưng đó là vì |, không phải { ... }. Bạn đề cập đến điều này trong câu hỏi. AFAIK, bạn có thể thực hiện trả về từ bên trong các hàm này bên trong một hàm.


Bash cũng cung cấp shoptnội trang và một trong nhiều tùy chọn của nó là:

lastpipe

Nếu được đặt và điều khiển công việc không hoạt động, trình bao sẽ chạy lệnh cuối cùng của một đường ống không được thực thi ở chế độ nền trong môi trường trình bao hiện tại.

Do đó, sử dụng một cái gì đó như thế này trong một tập lệnh làm cho bản sửa đổi sumcó sẵn sau vòng lặp:

FILECONTENT="12 Name
13 Number
14 Information"
shopt -s lastpipe   # Comment this out to see the alternative behaviour
sum=0
echo "$FILECONTENT" |
while read number name; do ((sum+=$number)); done
echo $sum

Thực hiện điều này tại dòng lệnh thường gặp lỗi 'kiểm soát công việc không hoạt động' (nghĩa là tại dòng lệnh, kiểm soát công việc đang hoạt động). Không thể kiểm tra điều này mà không sử dụng tập lệnh.

Ngoài ra, như đã được Gareth Rees lưu ý trong câu trả lời của mình , đôi khi bạn có thể sử dụng một chuỗi ở đây :

while read i; do echo $i; done <<< "$FILECONTENT"

Điều này không yêu cầu shopt; bạn có thể lưu một quá trình bằng cách sử dụng nó.


Thứ lỗi cho sự thiếu hiểu biết của tôi. Tôi biết đây là giải pháp đúng và tôi đã đánh dấu nó là câu trả lời để nó phù hợp với tôi. Nhưng bây giờ khi tôi chạy while read i; do echo $i; done < <(cat /etc/passwd); echo $iNó không trả về dòng cuối cùng hai lần. Tôi đang làm gì sai?
Wakan Tanka

@WakanTanka: Tôi đã phải thử nghiệm một chút ... Tôi tin rằng câu trả lời là việc đọc không thành công sẽ đặt lại ithành trống, vì vậy tiếng vọng sau vòng lặp vang lên một dòng trống.
Jonathan Leffler

1
Kudos cho tài liệu tham khảo Thay thế quy trình. Tôi đã không biết về.
Atcold

@Wakan Tanka: có kết quả tương tự như của bạn, tôi sử dụng while read i; do x=$i; done < <(cat /etc/passwd); echo i=$i; echo x=$xđã hoạt động, // có thể những ngày đó hành vi bash đã thay đổi?
yurenchen

Bạn là một người tiết kiệm cuộc sống! Đã tìm kiếm hàng giờ cho một giải pháp tương tự. Của bạn là cái duy nhất có hiệu quả.
Pat


0

Hàm này tạo bản sao $ NUM lần tệp jpg (bash)

function makeDups() {
NUM=$1
echo "Making $1 duplicates for $(ls -1 *.jpg|wc -l) files"
ls -1 *.jpg|sort|while read f
do
  COUNT=0
  while [ "$COUNT" -le "$NUM" ]
  do
    cp $f ${f//sm/${COUNT}sm}
    ((COUNT++))
  done
done
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.