Каков переносимый (POSIX) способ достижения подстановки процессов?

Это может произойти в x86_64 и мультибиблиотечном пакете. yum remove libstdc ++ пытается удалить 64-битную версию, но она не установлена. Поэтому в такой ситуации вам следует обратиться к пакету с помощью arch. То есть:

yum remove libstdc++-4.1.2-55.el5.i386
27
13.04.2017, 15:37
3 ответа

Эта возможность была введена в ksh (впервые документирована в ksh86) и использовала возможность /dev/fd/n (добавленную независимо в некоторых BSD и AT&T системах ранее). В ksh и вплоть до ksh93u это не будет работать, если в вашей системе нет поддержки /dev/fd/n. zsh, bash и ksh93u+ и выше могут использовать временные именованные трубы (именованные трубы добавлены в SysIII, я полагаю), где /dev/fd/n недоступны.

На системах, где /dev/fd/n доступны (POSIX не определяет их), вы можете сделать подстановку процессов самостоятельно (diff <(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

Однако это не работает с ksh93 в Linux, поскольку там shell pipes реализованы с помощью socketpairs, а не pipes, и открытие /dev/fd/3, где fd 3 указывает на сокет, не работает в Linux.

Хотя POSIX не определяет /dev/fd/n. Он определяет именованные трубы. Именованные трубы работают как обычные трубы, за исключением того, что вы можете получить к ним доступ из файловой системы. Проблема здесь в том, что вы должны создавать временные и очищать их после этого, что трудно сделать надежно, особенно учитывая, что POSIX не имеет стандартного механизма (например, mktemp -d, как в некоторых системах) для создания временных файлов или каталогов, и переносимая обработка сигналов (очистка после зависания или убийства) также трудно переносима.

Вы можете сделать что-то вроде:

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"

(здесь не рассматривается обработка сигналов).

33
27.01.2020, 19:39

Если нужно избежать потери переменной в полезном cmd | while read A B C, вместо:

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

вы можете использовать:

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

Итак, чтобы ответить на вопрос:

sort file1 | diff /dev/stdin /dev/stdout 2<<EOT
`sort file2`
EOT
3
27.01.2020, 19:39

Для этого можно использовать файлы heredoc и /dev/fd/n. Например, в bashможно сделать так:

#!/usr/bin/env bash

paste  <(echo "$SHELL") <(echo "$TERM") <(echo "$LANG")

но в POSIX sh вы должны сделать это:

#!/bin/sh

paste /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF /dev/fd/5 5<<-EOF 
$SHELL
EOF
$TERM
EOF
$LANG
EOF

Вывод такой же.

И чтобы ответить на вопрос, это работает:

#!/bin/sh

diff /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF
$(sort file1)
EOF
$(sort file2)
EOF

Выглядит неуклюже, но работает.

1
17.03.2021, 14:03

Теги

Похожие вопросы