的/ dev /标准输入与herestring(/dev/stdin with herestring

2019-07-21 07:16发布

我想一个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

Answer 1:

使用/dev/stdin ,因为你正试图获得一个句柄在文件系统中使用的名称标准输入(以这种方式可能是有问题/dev/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,标准输入。 然而,临时文件已经从文件系统链接断开,所以不通过文件系统名称引用,如访问/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


Answer 2:

bash解析某些文件的名字(例如/dev/stdin )特别,使他们即使他们不是在文件系统中实际存在的认可。 如果你的脚本没有#!/bin/bash顶部,和/dev/stdin是不是在你的文件系统,你的脚本可以使用运行/bin/sh ,这将预期/dev/stdin实际是一个文件。

(这应该,也许,不是一个答案,而是要评论奥斯汀的答案 。)



Answer 3:

$ cat ts.sh 
read b < "${1-/dev/stdin}"
echo $b

$ ./ts.sh <<< 'hello world'
hello world

对我来说没问题。 我使用bash 4.2.42在Mac OS X.



Answer 4:

你有一个错字这里

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

尝试

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


文章来源: /dev/stdin with herestring