我知道您可以创建一个文件描述符并将输出重定向到它。例如
exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.
Run Code Online (Sandbox Code Playgroud)
但是你可以在没有文件描述符的情况下做同样的事情:
FILE=/tmp/foo
echo a > "$FILE"
Run Code Online (Sandbox Code Playgroud)
我正在寻找一个很好的例子,说明何时必须使用额外的文件描述符。
一些 shell,如bash,支持进程替换,这是一种将进程输出呈现为文件的方法,如下所示:
$ diff <(sort file1) <(sort file2)
Run Code Online (Sandbox Code Playgroud)
但是,此构造不是POSIX,因此不可移植。如何处理替代的实现POSIX -友好的方式(即其中一个在工作/bin/sh)?
注意:问题不是问如何区分两个排序的文件——这只是一个人为的例子来演示进程替换!
我有一个应用程序会产生大量我不想存储到磁盘上的数据。该应用程序主要输出我不想使用的数据,而是一组必须拆分为单独文件的有用信息。例如,给定以下输出:
JUNK
JUNK
JUNK
JUNK
A 1
JUNK
B 5
C 1
JUNK
Run Code Online (Sandbox Code Playgroud)
我可以像这样运行应用程序三次:
./app | grep A > A.out
./app | grep B > B.out
./app | grep C > C.out
Run Code Online (Sandbox Code Playgroud)
这会让我得到我想要的,但需要太长时间。我也不想将所有输出转储到一个文件中并通过它进行解析。
有没有什么方法可以将上面显示的三个操作组合在一起,这样我只需要运行一次应用程序,仍然可以获得三个单独的输出文件?
我有这个命令:
cat somefile >file1 >file2
Run Code Online (Sandbox Code Playgroud)
执行此命令后,我无法弄清楚为什么其中file1没有任何内容。它应该具有第一个文件 ( somefile)的输出,但其中没有任何内容。
你能向我解释为什么它不从 复制或写入我的输出somefile吗?(file2包含我的输出,但不file1包含任何内容)
起初我认为这个答案是解决方案,但现在我认为我需要一个临时文件作为缓冲区。
这不可靠:
#!/bin/sh
echo 'OK' |
{
{
tee /dev/fd/3 | head --bytes=1 >&4
} 3>&1 | tail --bytes=+2 >&4
} 4>&1
Run Code Online (Sandbox Code Playgroud)
当我在终端中运行它时,有时我会得到:
好的
有时我会得到:
ķ
Ø
似乎完全随机。因此,作为一种解决方法,我将 的输出写入tail文件并stdout在管道完成后将其读回。
#!/bin/sh
echo 'OK' |
{
{
tee /dev/fd/3 | head --bytes=1 >&4
} 3>&1 | tail --bytes=+2 >file
} 4>&1
cat file
Run Code Online (Sandbox Code Playgroud)
这可以在dash没有临时文件的情况下完成吗?Shell 变量作为缓冲区也不是一个选项,因为输出可能包含 NUL 字节。
我有一个输出一些值/数字的脚本,我想将它们分成两个文件。我在看类似的东西:
./runme.sh | grep 'ook' >> ook.out | grep 'eek' >> eek.out
Run Code Online (Sandbox Code Playgroud)
在这种情况下,第二个管道不应采用第一个 grep 的输出,而是采用 runme.sh 的输出。那可能吗?
我正在使用 FFmpeg 并且我制作了一个自定义应用程序,它是一个 TCP 服务器。我在 ffmpeg 中使用重复输出。
我想要的是,对于每个输出,我想启动我的程序以侦听特定端口。例如我现在可以做什么:
ffmpeg -i "stream_link" -codec copy -f mpegts - \
| myprogram -h 127.0.0.1 -p 12345 -f -
Run Code Online (Sandbox Code Playgroud)
我的程序从 ffmpeg 获取数据并将它们存储在服务器中。现在,我不能做以下事情
ffmpeg -i "stream_link" -codec copy -f mpegts - -codec copy -f flv - \
| myprogram -h 127.0.0.1 -p 12345 -f - \
| myprogram -h 127.0.0.1 -p 12345 -f -
Run Code Online (Sandbox Code Playgroud)
我想你得到了我。我正在尝试输出 2 个不同的容器 mpegts、flv 并再次打开我的程序的 2 个实例。那么我如何才能做到呢?
这个问题只与管道有关。我只是举了一个使用 FFmpeg 的真实例子。
我想将标准输出发送到多个命令,但是我不确定如何从进程替换中的标准输入读取?
我的尝试:
$ echo foo >(cat /dev/stdin) >(cat /dev/stdin)
foo /dev/fd/63 /dev/fd/62
$ echo foo >(cat -) >(cat -)
foo /dev/fd/63 /dev/fd/62
$ echo foo >(cat <&3) >(cat <&3) 3<&0
foo /dev/fd/63 /dev/fd/62
-bash: 3: Bad file descriptor
-bash: 3: Bad file descriptor
Run Code Online (Sandbox Code Playgroud)
同一问题的替代版本:
$ cat file | tee &>/dev/null >(cmd1 /dev/stdin) >(cmd2 /dev/stdin)
Run Code Online (Sandbox Code Playgroud)
这样做的正确方法是什么?
有点重新问我的问题,因为我错误地用 bash shell 标签询问,并认为这是一个更合适的地方。
我正在 AWS DataPipeline 中编写一个连接到关系数据库的 shell 脚本,即使对于 SQL 错误,退出代码也是 0,因此我需要捕获 + 重定向 stderr。
我将 stderr 重定向到另一个文件以检查其内容,但仍然希望填充 stderr。原因是 DataPipeline 捕获所有 stderr 和 stdout 并将它们全部放入 1 个日志中。由于重定向,它不会从失败的 sql 命令中捕获 stderr。有没有办法仍然填充 stderr?我目前拥有的是:
/bin/snowsql -f /home/scripts/dev/dev.sql 2> /home/scripts/dev/stderr.txt
Run Code Online (Sandbox Code Playgroud)
以下内容适用于 Bash:
/bin/snowsql -f /home/scripts/dev/dev.sql 2> >(tee /home/scripts/dev/stderr.txt >&2)
Run Code Online (Sandbox Code Playgroud)
我找不到 shell 进程替换的正确语法。在 shell 中执行上述操作相当于什么?