Làm thế nào để mô phỏng quá trình thay thế trong Dash?


18

Trong bash, tôi có thể sử dụng Thay thế quy trình và xử lý đầu ra của một quy trình như thể đó là một tệp được lưu trên đĩa:

$ echo <(ls)
/dev/fd/63

$ ls -lAhF <(ls)
lr-x------ 1 root root 64 Sep 17 12:55 /dev/fd/63 -> pipe:[1652825]

Thật không may, Quá trình thay thế không được hỗ trợ dash.

Điều gì sẽ là cách tốt nhất để thi đua Process Substitutiontrong dấu gạch ngang?

Tôi không muốn lưu kết quả dưới dạng một tệp tạm thời ở đâu đó ( /tmp/) và sau đó phải xóa nó. Có cách nào khác không?


Tùy thuộc vào những gì bạn đang cố gắng làm, bạn có thể sử dụng đường ống.
Eric Renouf

Thành thật mà nói, nếu tính di động không phải là mối quan tâm chính của bạn ở đây thì việc cài đặt bashtrên thiết bị của bạn có dễ dàng hơn không?
Arkadiusz Drabchot

1
Ví dụ bạn cung cấp trong thông báo tiền thưởng xảy ra là chủ đề của câu trả lời được liên kết này . Như được hiển thị ở đó, một phiên bản đơn giản của câu trả lời của Gilles (giả sử có sẵn /dev/fdvà sử dụng xz -cd <file>thay vì cat <file> | xz -d) có thể xz -cd "$1" | { xz -cd "$2" | { diff /dev/fd/3 /dev/fd/4; } 3<&0; } 4<&0.
fra-san

1
@ fra-san - đó thực sự là những gì tôi cần. Bạn có thể làm cho nó một câu trả lời nếu bạn muốn. Cảm ơn.
Martin Vegter

Câu trả lời:


4

Câu hỏi trong thông báo tiền thưởng hiện tại:

ví dụ chung là quá phức tạp. Ai đó có thể vui lòng giải thích làm thế nào để thực hiện ví dụ sau đây?diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

dường như có một câu trả lời ở đây .

Như được hiển thị trong câu trả lời của Gilles , ý tưởng chung là gửi đầu ra của lệnh "nhà sản xuất" đến các tệp thiết bị mới 1 ở các giai đoạn khác nhau của đường ống, làm cho chúng có sẵn cho các lệnh "người tiêu dùng", có thể lấy tên tệp làm đối số ( giả sử rằng hệ thống của bạn cung cấp cho bạn quyền truy cập vào mô tả tệp như /dev/fd/X).

Cách đơn giản nhất để đạt được những gì bạn đang tìm kiếm có lẽ là:

xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0

(Sử dụng file1.xzthay "$1"cho khả năng đọc và xz -cdthay cat ... | xz -dvì vì một lệnh là đủ).

Đầu ra của lệnh "nhà sản xuất" đầu tiên xz -cd file1.xz, được dẫn đến một lệnh ghép ( {...}); nhưng, thay vì được sử dụng ngay lập tức như là đầu vào tiêu chuẩn của lệnh tiếp theo, nó được sao chép thành mô tả tệp 3và do đó có thể truy cập được mọi thứ bên trong lệnh ghép như /dev/fd/3. Đầu ra của lệnh "nhà sản xuất" thứ hai xz -cd file2.xz, không tiêu thụ đầu vào tiêu chuẩn cũng như bất cứ thứ gì từ bộ mô tả tệp 3, sau đó được dẫn đến lệnh "người tiêu dùng" diff, đọc từ đầu vào tiêu chuẩn và từ /dev/fd/3.

Sao chép mô tả đường ống và tệp có thể được thêm vào để cung cấp tệp thiết bị cho nhiều lệnh "nhà sản xuất" khi cần, ví dụ:

xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0

Mặc dù có thể không liên quan trong bối cảnh câu hỏi cụ thể của bạn, nhưng đáng chú ý là:

  1. cmd1 <(cmd2) <(cmd3), cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )có tác dụng tiềm năng khác nhau trên môi trường thực thi ban đầu.

  2. Trái với những gì xảy ra trong cmd1 <(cmd2) <(cmd3), cmd3cmd1trong cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0sẽ không thể đọc bất kỳ đầu vào từ người dùng. Điều đó sẽ yêu cầu mô tả tập tin thêm. Ví dụ, để phù hợp

    diff <(echo foo) <(read var; echo "$var")
    

    bạn sẽ cần một cái gì đó như

    { echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0
    

1 Nhiều hơn về chúng có thể được tìm thấy trên U & L, ví dụ như trong Hiểu / dev và các thư mục con và tệp của nó .


12

Bạn có thể tái tạo những gì vỏ làm dưới mui xe bằng cách làm ống nước bằng tay. Nếu hệ thống của bạn có các mục, bạn có thể sử dụng xáo trộn mô tả tệp: bạn có thể dịch/dev/fd/NNN

main_command <(produce_arg1) <(produce_arg2) >(consume_arg3) >(consume_arg4)

đến

{ produce_arg1 |
  { produce_arg2 |
    { main_command /dev/fd5 /dev/fd6 /dev/fd3 /dev/fd4 </dev/fd/8 >/dev/fd/9; } 5<&0 3>&1 |
    consume_arg3; } 6<&0 4>&1; |
  consume_arg4; } 8<&0 9>&1

Tôi đã đưa ra một ví dụ phức tạp hơn để minh họa nhiều đầu vào và đầu ra. Nếu bạn không cần đọc từ đầu vào tiêu chuẩn và lý do duy nhất bạn đang sử dụng thay thế quy trình là lệnh yêu cầu tên tệp rõ ràng, bạn chỉ cần sử dụng /dev/stdin:

main_command <(produce_arg1)
produce_arg1 | main_command /dev/stdin

Nếu không , bạn cần sử dụng một đường ống có tên . Một ống có tên là một mục nhập thư mục, vì vậy bạn cần tạo một tệp tạm thời ở đâu đó, nhưng tệp đó chỉ là một tên, nó không chứa bất kỳ dữ liệu nào./dev/fd/NNN

tmp=$(mktemp -d)
mkfifo "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
produce_arg1 >"$tmp/f1" &
produce_arg2 >"$tmp/f2" &
consume_arg3 <"$tmp/f3" &
consume_arg4 <"$tmp/f4" &
main_command "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
rm -r "$tmp"

2
</dev/fd/8 >/dev/fd/9không tương đương với <&8 >&9trên Linux và nên tránh ở đó.
Stéphane Chazelas

@Gilles - Tôi bối rối bởi ví dụ phức tạp. Bạn có thể vui lòng chỉ ra cách thi đua : diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)?
Martin Vegter

3

Ai đó có thể vui lòng giải thích làm thế nào để thực hiện ví dụ sau đây?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

Tôi nghĩ rằng các đường ống được đặt tên là đơn giản để mò mẫm hơn các chuyển hướng, vì vậy trong các thuật ngữ đơn giản nhất:

mkfifo p1 p2               # create pipes
cat "$2" | xz -d > p1 &    # start the commands in the background
cat "$1" | xz -d > p2 &    #    with output to the pipes
diff p1 p2                 # run 'diff', reading from the pipes
rm p1 p2                   # remove them at the end

p1p2được đặt tên tạm thời, họ có thể được đặt tên bất cứ điều gì.

Sẽ thông minh hơn khi tạo các đường ống trong /tmp, ví dụ như trong một thư mục như câu trả lời của Gilles hiển thị và lưu ý rằng bạn không cần catở đây, vì vậy:

tmpdir=$(mktemp -d)
mkfifo "$tmpdir/p1" "$tmpdir/p2"
xz -d < "$2" > "$tmpdir/p1" &
xz -d < "$1" > "$tmpdir/p2" &
diff "$tmpdir/p1" "$tmpdir/p2"
rm -r "$tmpdir"

(Bạn có thể có thể thoát khỏi mà không có dấu ngoặc kép, vì mktempcó khả năng tạo ra tên tệp "đẹp".)

Giải pháp đường ống có cảnh báo rằng nếu lệnh chính ( diff) chết trước khi đọc tất cả đầu vào, các quy trình nền có thể bị treo.


0

Thế còn:

cat "$2" | xz -d | diff /dev/sdtin /dev/stderr 2<<EOT
`cat "$1" | xz -d`
EOT
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.