下面的Perl脚本(my.pl)既可以从命令行参数中的文件读取,也可以从标准输入(STDIN)读取:
while (<>) {
print($_);
}
Perl my.pl将从标准输入中读取,而Perl my.pl .txt将从a.txt中读取。这很方便。
Bash中也有类似的功能吗?
下面的Perl脚本(my.pl)既可以从命令行参数中的文件读取,也可以从标准输入(STDIN)读取:
while (<>) {
print($_);
}
Perl my.pl将从标准输入中读取,而Perl my.pl .txt将从a.txt中读取。这很方便。
Bash中也有类似的功能吗?
当前回答
这是最简单的方法:
#!/bin/sh
cat -
用法:
$ echo test | sh my_script.sh
test
要将stdin分配给变量,您可以使用:stdin =$(cat -)或只是简单的stdin =$(cat)作为操作符是不必要的(根据@mklement0注释)。
要解析标准输入中的每一行,请尝试以下脚本:
#!/bin/bash
while IFS= read -r line; do
printf '%s\n' "$line"
done
要从文件或stdin中读取(如果参数不存在),您可以将其扩展为:
#!/bin/bash
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
Notes: - read -r - Do not treat a backslash character in any special way. Consider each backslash to be part of the input line. - Without setting IFS, by default the sequences of Space and Tab at the beginning and end of the lines are ignored (trimmed). - Use printf instead of echo to avoid printing empty lines when the line consists of a single -e, -n or -E. However there is a workaround by using env POSIXLY_CORRECT=1 echo "$line" which executes your external GNU echo which supports it. See: How do I echo "-e"?
参见:当没有参数传递时如何读取stdin ?在stackoverflow SE
其他回答
从stdin读入变量或从文件读入变量。
现有答案中的大多数示例使用循环,当它从stdin读取时立即回显每一行。这可能不是你真正想做的。
在许多情况下,您需要编写一个脚本来调用只接受file参数的命令。但是在你的脚本中,你可能也想要支持stdin。在这种情况下,您需要首先读取完整的stdin,然后将其作为文件提供。
让我们看一个例子。下面的脚本打印一个证书的证书详细信息(以PEM格式),该证书可以作为文件传递,也可以通过stdin传递。
# print-cert script
content=""
while read line
do
content="$content$line\n"
done < "${1:-/dev/stdin}"
# Remove the last newline appended in the above loop
content=${content%\\n}
# Keytool accepts certificate only via a file, but in our script we fix this.
keytool -printcert -v -file <(echo -e $content)
# Read from file
cert-print mycert.crt
# Owner: CN=....
# Issuer: ....
# ....
# Or read from stdin (by pasting)
cert-print
#..paste the cert here and press enter
# Ctl-D
# Owner: CN=....
# Issuer: ....
# ....
# Or read from stdin by piping to another command (which just prints the cert(s) ). In this case we use openssl to fetch directly from a site and then print its info.
echo "" | openssl s_client -connect www.google.com:443 -prexit 2>/dev/null \
| sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' \
| cert-print
# Owner: CN=....
# Issuer: ....
# ....
作为一种变通方法,你可以使用/dev目录下的stdin设备:
....| for item in `cat /dev/stdin` ; do echo $item ;done
我认为这是最直接的方法:
$ cat reader.sh
#!/bin/bash
while read line; do
echo "reading: ${line}"
done < /dev/stdin
--
$ cat writer.sh
#!/bin/bash
for i in {0..5}; do
echo "line ${i}"
done
--
$ ./writer.sh | ./reader.sh
reading: line 0
reading: line 1
reading: line 2
reading: line 3
reading: line 4
reading: line 5
每当IFS中断输入流时,回显解决方案就添加新行。@fgm的回答可以稍微修改一下:
cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}"
下面的解决方案从文件读取(如果脚本调用时将文件名作为第一个参数$1),否则从标准输入读取。
while read line
do
echo "$line"
done < "${1:-/dev/stdin}"
替换${1:-…}如果定义了,则接受$1。否则,使用自己进程的标准输入的文件名。