下面的Perl脚本(my.pl)既可以从命令行参数中的文件读取,也可以从标准输入(STDIN)读取:

while (<>) {
   print($_);
}

Perl my.pl将从标准输入中读取,而Perl my.pl .txt将从a.txt中读取。这很方便。

Bash中也有类似的功能吗?


当前回答

从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: ....
# ....

其他回答

每当IFS中断输入流时,回显解决方案就添加新行。@fgm的回答可以稍微修改一下:

cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}"

问题中的Perl循环从命令行上的所有文件名参数读取,如果没有指定文件,则从标准输入读取。如果没有指定文件,我看到的答案似乎都在处理单个文件或标准输入。

虽然经常被嘲笑为UUOC(无用地使用猫),但有时猫是工作的最佳工具,这是有争议的:

cat "$@" |
while read -r line
do
    echo "$line"
done

唯一的缺点是它创建了一个在子shell中运行的管道,因此while循环中的变量赋值之类的东西在管道之外是不可访问的。bash的方法是进程替换:

while read -r line
do
    echo "$line"
done < <(cat "$@")

这使得while循环在主shell中运行,因此在循环中设置的变量可以在循环外访问。

下面的解决方案从文件读取(如果脚本调用时将文件名作为第一个参数$1),否则从标准输入读取。

while read line
do
  echo "$line"
done < "${1:-/dev/stdin}"

替换${1:-…}如果定义了,则接受$1。否则,使用自己进程的标准输入的文件名。

代码${1:-/dev/stdin}只理解第一个参数,所以你可以这样使用:

ARGS='$*'
if [ -z "$*" ]; then
  ARGS='-'
fi
eval "cat -- $ARGS" | while read line
do
   echo "$line"
done

以下是使用标准sh(在Debian上用Dash测试)的工作,相当可读,但这是一个品味问题:

if [ -n "$1" ]; then
    cat "$1"
else
    cat
fi | commands_and_transformations

详细信息:如果第一个参数非空,则cat该文件,否则cat标准输入。然后整个if语句的输出由command_and_transforms处理。