bash /dev/stdin 带有这里字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15330402/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
/dev/stdin with herestring
提问by Steven Penny
I would like a Bash script that can take input from a file or stdin, much like grep, for example
我想要一个可以从文件或标准输入中获取输入的 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
all works beautifully. However with the following script
一切都很好。但是使用以下脚本
read b < "${1-/dev/stdin}"
echo $b
It fails if using a herestring
如果使用 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
回答by Austin Phillips
Using /dev/stdinin this manner can be problematic because you are attempting to get a handle to stdin using a name in the filesystem (/dev/stdin) rather than using the file descriptor which bash has already handed you as stdin (file descriptor 0).
/dev/stdin以这种方式使用可能会出现问题,因为您试图使用文件系统 ( /dev/stdin) 中的名称来获取 stdin 的句柄,而不是使用 bash 已经作为 stdin(文件描述符 0)传递给您的文件描述符。
Here's a small script for you to test:
这是一个小脚本供您测试:
#!/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"
On my cygwin installation this produces the following:
在我的 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:
What this output shows is that bash is creating a temporary file to hold your HERE document (/tmp/sh-thd-1362969584) and making it available on file descriptor 0, stdin. However, the temporary file has already been unlinked from the file system and so is not accessible by reference through a file system name such as /dev/stdin. You can get the contents by reading file descriptor 0, but not by trying to open /dev/stdin.
此输出显示的是 bash 正在创建一个临时文件来保存您的 HERE 文档 ( /tmp/sh-thd-1362969584) 并使其在文件描述符 0 (stdin) 上可用。但是,临时文件已与文件系统取消链接,因此无法通过文件系统名称(如/dev/stdin. 您可以通过读取文件描述符 0 来获取内容,但不能通过尝试打开/dev/stdin.
On Linux, the ./sscript above gives the following, showing that the file has been unlinked:
在 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
Change your script to use the stdin supplied, rather than trying to reference through /dev/stdin.
更改您的脚本以使用提供的标准输入,而不是尝试通过/dev/stdin.
if [ -n "" ]; then
read b < ""
else
read b
fi
回答by chepner
bashparses some file names (like /dev/stdin) specially, so that they are recognized even if they are not actually present in the file system. If your script doesn't have #!/bin/bashat the top, and /dev/stdinisn't in your file system, your script may be run using /bin/sh, which would expect /dev/stdinto actually be a file.
bash/dev/stdin专门解析一些文件名(如),以便即使它们实际上不存在于文件系统中也能被识别。如果您的脚本没有#!/bin/bash顶部,并且/dev/stdin不在您的文件系统中,则您的脚本可能会使用 运行/bin/sh,这/dev/stdin实际上是一个文件。
(This should, perhaps, not be an answer, but rather a comment to Austin's answer.)
(这也许不应该是答案,而是对奥斯汀答案的评论。)
回答by zzk
$ cat ts.sh
read b < "${1-/dev/stdin}"
echo $b
$ ./ts.sh <<< 'hello world'
hello world
No problem for me. I'm using bash 4.2.42 on Mac OS X.
对我来说没问题。我在 Mac OS X 上使用 bash 4.2.42。
回答by djoot
You got a typo here
你在这里打错字了
read b < "${1-/dev/stdin}"
Try
尝试
read b < "${1:-/dev/stdin}"

