答案1
该功能是由ksh
(首先在 ksh86 中记录)引入的,并且正在使用该功能(之前在一些 BSD 和 AT&T 系统中独立添加)。在ksh93u 及之前版本中,除非您的系统支持. zsh、bash 及以上版本可以在不可用的情况下使用临时命名管道(System III 中添加的命名管道) 。/dev/fd/n
ksh
/dev/fd/n
ksh93u+
/dev/fd/n
在可用的系统上(POSIX 没有指定这些系统),您可以自己进行进程替换(例如,):/dev/fd/n
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
然而,这在 Linux 上不起作用ksh93
,因为 shell 管道是用套接字对而不是管道实现的,并且打开/dev/fd/3
fd 3 指向套接字的位置在 Linux 上不起作用。
尽管 POSIX 没有指定,但它确实指定了命名管道。命名管道的工作方式与普通管道类似,只是您可以从文件系统访问它们。这里的问题是,您必须创建临时文件并在事后进行清理,这很难可靠地完成,特别是考虑到 POSIX 没有标准机制(如某些系统上的机制)来创建临时文件或目录以及信号处理(挂断或杀死时清理)也很难移植。/dev/fd/n
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"
cleanup
(这里不考虑信号处理)。
答案2
您可以依靠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
它看起来很笨重,但是很有效。
答案3
如果需要避免丢失有用的变量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