如何从Bash中的文件或标准input读取?
在Perl中,以下代码将从命令行参数或stdin中指定的文件中读取:
while (<>) { print($_); } 这很方便。 我只是想知道从bash中的文件或标准input读取最简单的方法是什么。
 如果使用文件名作为第一个参数$1调用脚本,则从文件读取以下解决scheme,否则从标准input读取脚本。 
 while read line do echo "$line" done < "${1:-/dev/stdin}" 
 如果定义${1:-...} ,那么replace${1:-...} $1 ,否则使用自己进程的标准input的文件名。 
也许最简单的解决scheme是用合并redirect操作符redirectstdin:
 #!/bin/bash less <&0 
标准input是文件描述符零。 上面发送到您的bash脚本inputinput到less的标准input。
阅读更多关于文件描述符redirect的信息 。
这是最简单的方法:
 #!/bin/sh cat - 
用法:
 $ echo test | sh my_script.sh test 
 要将stdin分配给variables,可以使用: STDIN=$(cat -)或者仅仅是STDIN=$(cat)因为操作符是不必要的(根据@ mklement0注释 )。 
要从标准inputparsing每一行,请尝试以下脚本:
 #!/bin/bash while IFS= read -r line; do printf '%s\n' "$line" done 
要从文件或标准input读取(如果参数不存在),可以将其扩展为:
 #!/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") 
笔记:
–
read -r– 不要以任何特殊的方式处理反斜线字符。 考虑每个反斜杠是input行的一部分。– 在不设置
IFS的情况下,默认情况下会忽略线条开始和结束处的空格和制表符的序列(修剪)。– 使用
printf而不是echo来避免在行由单个-e,-n或-E组成时打印空行。 然而,通过使用env POSIXLY_CORRECT=1 echo "$line"来执行你的外部 GNUecho,这是一个解决方法。 请参阅: 我如何回显“-e”?
请参阅: 如何读取stdin时没有parameter passing? 在stackoverflow SE
我认为这是直截了当的方式:
 $ 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中断inputstream时, echo解决scheme都会添加新行。  @ fgm的答案可以修改一下: 
 cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}" 
问题中的Perl循环从命令行中的所有文件名参数中读取,如果没有指定文件,则从标准input中读取。 如果没有指定文件,我看到的答案似乎都处理单个文件或标准input。
 虽然经常被人们嘲笑为UUOC (无用cat ),但有时候cat是最好的工具,而这也是其中之一: 
 cat "$@" | while read -r line do echo "$line" done 
 唯一的缺点就是它创build了一个在子shell中运行的pipe道,所以像while循环中的variables赋值之类的东西在stream水线之外是不可访问的。  bash方式是stream程replace : 
 while read -r line do echo "$line" done < <(cat "$@") 
 这使得while循环在主shell中运行,因此循环中设置的variables可以在循环外部访问。 
  Perl的行为,在OP中给出的代码可以不带任何或几个参数,如果一个参数是一个连字符-这被理解为标准input。 而且,总是可以用$ARGV来指定文件名。 到目前为止所给出的答案都没有真正模仿Perl在这些方面的行为。 这是纯粹的Bash可能性。 诀窍是适当地使用exec 。 
 #!/bin/bash (($#)) || set -- - while (($#)); do { [[ $1 = - ]] || exec < "$1"; } && while read -r; do printf '%s\n' "$REPLY" done shift done 
 文件名在$1可用。 
 如果没有给出论据,我们人为地设置-作为第一个位置参数。 然后我们循环参数。 如果一个参数不是- ,我们使用execredirect来自文件名的标准input。 如果这个redirect成功,我们循环一个while循环。 我正在使用标准的REPLYvariables,在这种情况下,您不需要重置IFS 。 如果你想要另一个名字,你必须像这样重置IFS (当然,除非你不需要这个,并且知道你在做什么): 
 while IFS= read -r line; do printf '%s\n' "$line" done 
更精确地…
 while IFS= read -r line ; do printf "%s\n" "$line" done < file 
请尝试下面的代码:
 while IFS= read -r line; do echo "$line" done < file 
 代码${1:-/dev/stdin}只会理解第一个参数,所以呢,这个怎么样。 
 ARGS='$*' if [ -z "$*" ]; then ARGS='-' fi eval "cat -- $ARGS" | while read line do echo "$line" done 
 下面的内容适用于标准的sh (用Debian上的dashtesting)并且非常易读,但是这是一个有趣的问题: 
 if [ -n "$1" ]; then cat "$1" else cat fi | commands_and_transformations 
 详情:如果第一个参数是非空的,那么cat那个文件,否则cat标准input。 然后整个if语句的输出由commands_and_transformations处理。 
怎么样
 for line in `cat`; do something($line); done