8

grepたとえば、ファイルまたはstdinから入力を受け取ることができるBashスクリプトが欲しいです。

$ 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
4

4 に答える 4

11

この方法で使用すると、bashがすでにstdin(ファイル記述子0)として渡したファイル記述子を使用するのではなく/dev/stdin、ファイルシステム()の名前を使用してstdinへのハンドルを取得しようとするため、問題が発生する可能性があります。/dev/stdin

テストするための小さなスクリプトを次に示します。

#!/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がヒアドキュメント(/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

を介して参照しようとするのではなく、提供されたstdinを使用するようにスクリプトを変更します/dev/stdin

if [ -n "$1" ]; then
    read b < "$1"
else
    read b
fi
于 2013-03-11T03:35:59.850 に答える
1

bash一部のファイル名(など)を特別に解析し/dev/stdinて、ファイルシステムに実際に存在していなくても認識されるようにします。スクリプト#!/bin/bashの上部/dev/stdinがなく、ファイルシステムにない場合は、を使用してスクリプトを実行できます。これは、実際にはファイル/bin/shであると想定されます。/dev/stdin

(これはおそらく答えではなく、オースティンの答えへのコメントであるはずです。)

于 2013-03-11T12:41:51.003 に答える
0
$ cat ts.sh 
read b < "${1-/dev/stdin}"
echo $b

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

私には問題ない。MacOSXでbash4.2.42を使用しています。

于 2013-03-11T03:25:23.340 に答える
-1

ここにタイプミスがあります

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

試す

read b < "${1:-/dev/stdin}"
于 2013-03-11T03:46:20.410 に答える