Đường ống cho đầu ra vòng lặp ngăn chặn sửa đổi biến cục bộ


11

Tôi đang cố gắng viết một hàm bash đơn giản, lấy các đối số của nó, một số tệp và / hoặc thư mục. Nó nên:

  1. Đủ điều kiện tên tập tin.
  2. Sắp xếp chúng.
  3. Loại bỏ các bản sao.
  4. In tất cả những gì thực sự tồn tại.
  5. Trả về số lượng tệp không tồn tại.

Tôi có một kịch bản gần như làm những gì tôi muốn, nhưng rơi vào việc sắp xếp. Giá trị trả về của tập lệnh khi nó đứng là chính xác, nhưng đầu ra không (không được sắp xếp và trùng lặp). Nếu tôi bỏ ghi chú | sort -unhư đã chỉ ra, đầu ra là chính xác nhưng giá trị trả về luôn luôn 0.

Các giải pháp đơn giản của NB để giải quyết vấn đề được hoan nghênh nhưng câu hỏi thực sự là tại sao điều này lại xảy ra trong mã tôi có. Đó là, tại sao việc thêm đường ống dường như dừng tập lệnh tăng biến r?

Đây là kịch bản:

function uniqfile
{
    local r=0 

    for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done #| sort -u    ## remove that comment

    return $r
}

Chỉ là một quan sát nhỏ. Bạn có thể giảm for arg in "$@"xuống for arg. "Nếu 'trong TỪ ...;' không có mặt, thì 'trong "$ @"' được giả sử. " - trợ giúp cho
manatwork

Câu trả lời:


15

Đây là một cạm bẫy bash nổi tiếng, do tính năng này :

Mỗi lệnh trong một đường ống được thực thi như một quy trình riêng biệt (nghĩa là trong một lớp con).

để các biến được sửa đổi là cục bộ của lớp con và không thể nhìn thấy một lần nữa trong phần gốc.

Để tránh điều đó, hãy viết lại mã của bạn để tránh đường ống dẫn, với sự thay thế quy trình:

 for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done > >(sort -u)

Cảm ơn bạn. Thật tuyệt. Tôi tự hỏi nếu bạn có thể cho tôi biết tên của >(..command..)công trình. Tôi nghĩ rằng tôi biết làm thế nào nó hoạt động nhưng cảm thấy tôi nên đọc thêm.
tjm

2
@tjm: nó được gọi là quá trình thay thế
enzotib

Quá trình thay thế trong Bash có nhiều dạng: tldp.org/LDP/abs/html/
process

Thay thế quá trình là một hình thức giao tiếp giữa các quá trình cho phép đầu vào hoặc đầu ra của lệnh xuất hiện dưới dạng tệp. Lệnh được thay thế trong dòng, trong đó một tên tệp thường xảy ra , bởi vỏ lệnh. Điều này cho phép các chương trình thường chỉ chấp nhận các tệp để đọc trực tiếp hoặc ghi vào chương trình khác.
tộc

3

Việc | sort -ubuộc bit trước (toàn bộ vòng lặp for) chạy trong một quy trình phụ (bash cần 'STDOUT' để chuyển hướng vào sort'STDIN'. (Internet dường như nghĩ kshbashxử lý trường hợp này hơi khác .. trước hoặc cuối lệnh trong chuỗi ống được đặt vào một khung con?)

Chủ đề này đi qua một vấn đề tương tự, và có một giải pháp gọn gàng ở cuối: http://ubuntuforums.org/showthread.php?t=312017

đoạn trích
    #!/bin/bash
    exec 3< <(du | sort -n)  

    n=0
    while read size dir; do
      [ $size -gt 1000 ] && ((n++))
    done <&3
    exec 3<&-

    echo "Found $n too big files"
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.