Cách di động (POSIX) để đạt được sự thay thế quá trình là gì?


25

Một số shell, như bash, hỗ trợ Thay thế quy trình , đó là một cách để trình bày đầu ra của quy trình dưới dạng tệp, như sau:

$ diff <(sort file1) <(sort file2)

Tuy nhiên, cấu trúc này không phải là POSIX và do đó, không phải là di động. Làm thế nào có thể đạt được sự thay thế theo cách thân thiện với POSIX (tức là một hoạt động trong /bin/sh) ?

lưu ý: câu hỏi không hỏi làm thế nào để tìm khác biệt hai tệp được sắp xếp - đó chỉ là một ví dụ giả định để chứng minh sự thay thế quá trình !


mywiki.wooledge.org/ProcessSubstlation có một lưu ý rằng mywiki.wooledge.org/NamedPipes có thể được sử dụng ..
Sundeep


1
POSIX không yêu cầu /bin/shphải là vỏ POSIX, chỉ có một lệnh được gọi shở đâu đó trong môi trường phù hợp là tuân thủ POSIX. Chẳng hạn, trên Solaris 10, /bin/shkhông phải là vỏ POSIX, nó là vỏ Bourne cổ và vỏ POSIX nằm trong /usr/xpg4/bin/sh.
Stéphane Chazelas

Câu trả lời:


17

Tính năng đó được giới thiệu bởi ksh(tài liệu đầu tiên trong ksh86) và đang sử dụng /dev/fd/ntính năng này (được thêm độc lập trong một số hệ thống BSD và AT & T trước đó). Trong kshvà lên đến ksh93u, nó sẽ không hoạt động trừ khi hệ thống của bạn có hỗ trợ cho / dev / fd / n. zsh, bash và ksh93u+ở trên có thể sử dụng các đường ống được đặt tên tạm thời (tên ống được thêm vào trong SysIII tôi tin) trong đó / dev / fd / n không có sẵn.

Trên các hệ thống có sẵn (POSIX không chỉ định các hệ thống đó), bạn có thể tự thay thế quy trình ( ) bằng:/dev/fd/ndiff <(cmd1) <(cmd2)

{
  cmd1 4<&- | {
    # in here fd 3 points to the reading end of the pipe
    # from cmd1, while fd 0 has been restored from the original
    # stdin (saved on fd 4, now closed as no longer needed)

    cmd2 3<&- | diff /dev/fd/3 -

  } 3<&0 <&4 4<&- # restore the original stdin for cmd2

} 4<&0 # save a copy of stdin for cmd2

Tuy nhiên, điều đó không hoạt động với ksh93Linux như ở đó, các ống vỏ được triển khai với các ổ cắm thay vì các ống và mở /dev/fd/3trong đó fd 3 điểm cho một ổ cắm không hoạt động trên Linux.

Mặc dù POSIX không chỉ định . Nó chỉ định đường ống được đặt tên. Các ống được đặt tên hoạt động như các ống thông thường ngoại trừ việc bạn có thể truy cập chúng từ hệ thống tệp. Vấn đề ở đây là bạn phải tạo tạm thời và dọn sạch sau đó, điều này rất khó thực hiện, đặc biệt khi xem xét rằng POSIX không có cơ chế tiêu chuẩn (như được tìm thấy trên một số hệ thống) để tạo tệp hoặc thư mục tạm thời và xử lý tín hiệu một cách hợp lý (để dọn dẹp khi bị treo hoặc giết) cũng khó thực hiện./dev/fd/nmktemp -d

Bạn có thể làm một cái gì đó như:

tmpfifo() (
  n=0
  until
    fifo=$1.$$.$n
    mkfifo -m 600 -- "$fifo" 2> /dev/null
  do
    n=$((n + 1))
    # give up after 20 attempts as it could be a permanent condition
    # that prevents us from creating fifos. You'd need to raise that
    # limit if you intend to create (and use at the same time)
    # more than 20 fifos in your script
    [ "$n" -lt 20 ] || exit 1
  done
  printf '%s\n' "$fifo"
)

cleanup() { rm -f -- "$fifo"; }
fifo=$(tmpfifo /tmp/fifo) || exit

cmd2 > "$fifo" & cmd1 | diff - "$fifo"
rm -f -- "$fifo"

(không quan tâm đến việc xử lý tín hiệu ở đây).


Ví dụ về đường ống có tên hoàn toàn rõ ràng đối với tôi (tôi đoán 10 là giới hạn tùy ý?) Nhưng tôi không thể tìm ra /dev/fd/nví dụ của bạn . Tại sao mô tả 4 đóng hai lần? (Và mô tả cũng vậy 3.) Tôi bị lạc.
tự đại diện

@Wildcard, nó đã đóng cho các lệnh không cần nó. Ở đây, chỉ có diff cần fd 3. Không ai cần fd 4, nó chỉ được sử dụng để truyền stdin gốc tới cmd2( dup2(0,4)ở bên ngoài {...}, được khôi phục với dup2(4,0)bên trong {...}).
Stéphane Chazelas

Bạn có thể sử dụng mktemp -dđể giúp đảm bảo bạn có thể nhận được các FIFO, vì không ai nên viết thư mục tạm thời ngẫu nhiên hoàn toàn mới của bạn.
Daniel H

@DanielH, tôi đã đề cập đến mktemp -d. Nhưng đó không phải là lệnh tiêu chuẩn / POSIX.
Stéphane Chazelas

Huh, tôi đã không nhận ra điều đó. Rất tiếc. Tìm kiếm nhanh dường như cho thấy hầu hết các hệ thống đều hỗ trợ nó, vì vậy nó có thể vẫn có thể mang theo được, nhưng nó không phải là POSIX.
Daniel H

-1

Nếu cần để tránh mất biến trong hữu ích cmd | while read A B C, thay vì:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done < <(cmd)
echo "$VAR"

bạn có thể dùng:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done << EndOfText
`cmd`
EndOfText
echo "$VAR"

Vì vậy, để trả lời câu hỏi:

sort file1 | diff /dev/stdin /dev/stdout 2<<EOT
`sort file2`
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.