我想要一个可以从文件或标准输入获取输入的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
答案 0 :(得分:10)
以这种方式使用/dev/stdin
可能会有问题,因为您尝试使用文件系统中的名称(/dev/stdin
)来获取stdin句柄,而不是使用bash已经提交给您的文件描述符作为stdin(文件描述符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
答案 1 :(得分:1)
bash
专门解析一些文件名(如/dev/stdin
),这样即使它们实际上不存在于文件系统中,它们也会被识别。如果您的脚本顶部没有#!/bin/bash
,而/dev/stdin
不在您的文件系统中,那么您的脚本可能会使用/bin/sh
来运行,这可能会/dev/stdin
实际上是一个文件。
(这可能不是答案,而是对Austin's answer的评论。)
答案 2 :(得分:0)
$ cat ts.sh
read b < "${1-/dev/stdin}"
echo $b
$ ./ts.sh <<< 'hello world'
hello world
对我来说没问题。我在Mac OS X上使用bash 4.2.42。
答案 3 :(得分:-1)
你这里有一个错字
read b < "${1-/dev/stdin}"
尝试
read b < "${1:-/dev/stdin}"