bash命令行stdin如何传播到子进程

esm*_*mit 1 bash

我有一个脚本(file_redirection.sh),我尝试了各种组合来获得我想要的东西:

#!/bin/bash
echo "cat " $*
echo "cat $*"
echo "cat $@"
echo "cat " $@
Run Code Online (Sandbox Code Playgroud)

我希望能够跑

file_redirection.sh < tmp_file
Run Code Online (Sandbox Code Playgroud)

并让它显示

"cat < tmp_file"
Run Code Online (Sandbox Code Playgroud)

那可能吗?

Car*_*rum 6

不,那是不可能的.在<命令行上被shell脚本曾经运行前解释.你需要逃避<它才能进入你的脚本.例如:

file_redirection.sh \< tmp_file
Run Code Online (Sandbox Code Playgroud)

将生成您正在寻找的输出,但不会执行任何文件重定向.


cda*_*rke 5

你问“它是如何工作的”。UNIX 进程是使用称为 的操作创建的fork。这会获取当前进程的副本,并以非常有效的方式几乎完全按照原样复制它。复制还包括文件描述符表,其中 stdin、stdout、stderr、live。

当您进行重定向时,shell 会分叉,然后在子进程中更改它自己的文件描述符 (fd) 表。然后它在同一进程中使用相同的 fd 表运行新脚本。使用传统机制,进程唯一可以检查的是 stdin 是否连接到终端。在 C 中它使用,isatty()而在 bash 中你可以if [[ -t 0 ]]...(零是 stdin 的 fd)。

在 Linux(如果您使用的是 Linux)中,您有一个附加选项,fd 表以可读的形式显示在/proc/$$/fd($$ 给出当前进程 ID) 中。 ls -l /proc/$$/fd你会明白我的意思。

那么,我被重定向了吗?

if [[ -t 0 ]]   # is stdin a terminal?
then
    suffix=""
else
    line=$(ls -l /proc/$$/fd/0)
    file="${line##*-> }"

    suffix="< $file"
fi

echo "cat $suffix" 
Run Code Online (Sandbox Code Playgroud)

在命令行上:

/home/user1$ file_redirection.sh < tmp_file
cat < /home/qa/tmp_file
Run Code Online (Sandbox Code Playgroud)

但。你到底为什么要这样做?