bash -/dev/stdin 与 herestring

标签 bash cygwin stdin heredoc

我想要一个可以从文件或标准输入中获取输入的 Bash 脚本,例如 grep

$ cat hw.txt
Hello world

$ grep wor hw.txt
Hello world

$ echo 'Hello world' | grep wor
Hello world

$ grep wor <<< 'Hello world'
Hello world

一切都很好。但是使用以下脚本

read b < "${1-/dev/stdin}"
echo $b

如果使用herestring会失败

$ hw.sh hw.txt
Hello world

$ echo 'Hello world' | hw.sh
Hello world

$ hw.sh <<< 'Hello world'
/opt/a/hw.sh: line 1: /dev/stdin: No such file or directory

最佳答案

以这种方式使用 /dev/stdin 可能会有问题,因为您正试图使用​​文件系统中的名称 (/dev/stdin) 获取 stdin 的句柄而不是使用 bash 已经交给你的文件描述符作为标准输入(文件描述符 0)。

这是一个供您测试的小脚本:

#!/bin/bash

echo "INFO: Listing of /dev"
ls -al /dev/stdin

echo "INFO: Listing of /proc/self/fd"
ls -al /proc/self/fd

echo "INFO: Contents of /tmp/sh-thd*"
cat /tmp/sh-thd*

read b < "${1-/dev/stdin}"
echo "b: $b"

在我的 cygwin 安装中,这会产生以下内容:

./s <<< 'Hello world'


$ ./s <<< 'Hello world'
INFO: Listing of /dev
lrwxrwxrwx 1 austin None 15 Jan 23  2012 /dev/stdin -> /proc/self/fd/0
INFO: Listing of /proc/self/fd
total 0
dr-xr-xr-x 2 austin None 0 Mar 11 14:27 .
dr-xr-xr-x 3 austin None 0 Mar 11 14:27 ..
lrwxrwxrwx 1 austin None 0 Mar 11 14:27 0 -> /tmp/sh-thd-1362969584
lrwxrwxrwx 1 austin None 0 Mar 11 14:27 1 -> /dev/tty0
lrwxrwxrwx 1 austin None 0 Mar 11 14:27 2 -> /dev/tty0
lrwxrwxrwx 1 austin None 0 Mar 11 14:27 3 -> /proc/5736/fd
INFO: Contents of /tmp/sh-thd*
cat: /tmp/sh-thd*: No such file or directory
./s: line 12: /dev/stdin: No such file or directory
b: 

此输出显示 bash 正在创建一个临时文件来保存您的 HERE 文档 (/tmp/sh-thd-1362969584) 并使其在文件描述符 0 stdin 上可用。但是,临时文件已经与文件系统取消链接,因此无法通过文件系统名称(如 /dev/stdin)引用访问。您可以通过读取文件描述符 0 来获取内容,但不能通过尝试打开 /dev/stdin 来获取内容。

在 Linux 上,上面的 ./s 脚本给出以下内容,表明该文件已取消链接:

INFO: Listing of /dev
lrwxrwxrwx 1 root root 15 Mar 11 09:26 /dev/stdin -> /proc/self/fd/0
INFO: Listing of /proc/self/fd
total 0
dr-x------ 2 austin austin  0 Mar 11 14:30 .
dr-xr-xr-x 7 austin austin  0 Mar 11 14:30 ..
lr-x------ 1 austin austin 64 Mar 11 14:30 0 -> /tmp/sh-thd-1362965400 (deleted) <---- /dev/stdin not found
lrwx------ 1 austin austin 64 Mar 11 14:30 1 -> /dev/pts/12
lrwx------ 1 austin austin 64 Mar 11 14:30 2 -> /dev/pts/12
lr-x------ 1 austin austin 64 Mar 11 14:30 3 -> /proc/10659/fd
INFO: Contents of /tmp/sh-thd*
cat: /tmp/sh-thd*: No such file or directory
b: Hello world

更改您的脚本以使用提供的标准输入,而不是尝试通过 /dev/stdin 进行引用。

if [ -n "$1" ]; then
    read b < "$1"
else
    read b
fi

关于bash -/dev/stdin 与 herestring,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54327912/

相关文章:

linux - 将文件的一列与另一个文件匹配,并使用 bash 替换不同的列

linux - 比较驻留在不同目录中的文件的两个版本

windows - 如何使 babun/cygwin 主目录等于 windows 主目录?

c++ - 在 C++ 中忽略 std::cin 上的 EOF

python - 如何读取脚本中的标准输入?

linux - 如何根据条件使用 grep 删除行?

macos - 无法运行 shell 脚本

c++ - 编译 C++ 代码使其在 Windows 和 Linux 中表现相同

c - 刷新标准输入(消耗整个文本并在粘贴多行时继续)

Python——使用指定的shell执行shell命令