Bash: ống 'tìm' đầu ra thành 'readarray'


14

Tôi đang cố gắng tìm kiếm các tệp bằng cách sử dụng findvà đặt các tệp đó vào một mảng Bash để tôi có thể thực hiện các thao tác khác trên chúng (ví dụ: lshoặc grepchúng). Nhưng tôi không thể hiểu tại sao readarraykhông đọc findđầu ra khi nó được đưa vào.

Nói rằng tôi có hai tệp trong thư mục hiện tại file1.txtfile2.txt. Vì vậy, findđầu ra như sau:

$ find . -name "file*"
./file1.txt
./file2.txt

Vì vậy, tôi muốn chuyển nó thành một mảng có hai phần tử là các chuỗi "./file1.txt""./file2.txt"(không có dấu ngoặc kép, rõ ràng).

Tôi đã thử điều này, trong số một vài thứ khác:

$ declare -a FILES
$ find . -name "file*" | readarray FILES
$ echo "${FILES[@]}"; echo "${#FILES[@]}"

0

Như bạn có thể thấy từ echođầu ra, mảng của tôi trống.

Vậy chính xác thì tôi đang làm gì sai ở đây? Tại sao readarraykhông đọc findđầu ra là đầu vào tiêu chuẩn của nó và đưa các chuỗi đó vào mảng?

Câu trả lời:


21

Khi sử dụng một đường ống dẫn, bash chạy các lệnh trong subshells. Do đó, mảng được điền, nhưng trong một lớp con, vì vậy shell cha không có quyền truy cập vào nó.

Sử dụng thay thế quá trình:

readarray FILES < <(find)

Lưu ý rằng nó không hoạt động đối với các tệp có dòng mới trong tên của chúng. Nếu đó có thể là trường hợp, bạn cần một cú pháp phức tạp hơn:

readarray -d '' < <(find -print0)

3
Để hỗ trợ các dòng mới, điều này là đủ:readarray -d '' < <(find your_args -print0)
VasyaNovikov

6

Giải pháp đúng là:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

Điều đó tương tự với những gì BashFAQ 020 của Greg giải thích chi tiết và câu trả lời này bao gồm .

Không có vấn đề với các tệp có tên lẻ (không chứa NUL trong tên), với khoảng trắng hoặc dòng mới. Và kết quả được đặt trong một mảng, điều này làm cho nó hữu ích để xử lý thêm.


Tuyệt vời, đây là một giải pháp tốt hơn cho vấn đề tôi đã cố gắng giải quyết ngay từ đầu. +1 ngay khi đại diện của tôi đạt 15 :)
Villapx 17/2/2016

3

readarray cũng có thể đọc từ stdin

readarray FILES <<< "$(find . -name "file*")"; echo "${#FILES[@]}"

Điều này không hoạt động với find -print0việc bảo vệ chống lại tên tệp "không mong muốn".
roaima
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.