在Perl中,以下代码将从命令行args或stdin中指定的文件中读取:
while (<>) {
print($_);
}
Run Code Online (Sandbox Code Playgroud)
这很方便.我只是想知道在bash中从file或stdin读取的最简单方法是什么.
Fri*_*ner 374
如果使用文件名作为第一个参数调用脚本,则以下解决方案从文件读取,$1否则从标准输入调用.
while read line
do
echo "$line"
done < "${1:-/dev/stdin}"
Run Code Online (Sandbox Code Playgroud)
如果定义了替换${1:-...},$1则使用自己进程的标准输入的文件名.
Rya*_*yne 103
也许最简单的解决方案是使用合并重定向运算符重定向stdin:
#!/bin/bash
less <&0
Run Code Online (Sandbox Code Playgroud)
Stdin是文件描述符零.上面将输入管道传输给你的bash脚本到less的stdin.
ken*_*orb 74
这是最简单的方法:
#!/bin/sh
cat -
Run Code Online (Sandbox Code Playgroud)
用法:
$ echo test | sh my_script.sh
test
Run Code Online (Sandbox Code Playgroud)
要将stdin分配给变量,您可以使用:STDIN=$(cat -)或者只是STDIN=$(cat)因为不需要运算符(根据@ mklement0注释).
要从标准输入中解析每一行,请尝试以下脚本:
#!/bin/bash
while IFS= read -r line; do
printf '%s\n' "$line"
done
Run Code Online (Sandbox Code Playgroud)
要从文件或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")
Run Code Online (Sandbox Code Playgroud)
笔记:
-
read -r- 不要以任何特殊方式处理反斜杠字符.将每个反斜杠视为输入行的一部分.-如果不设置
IFS,默认情况下的序列Space和Tab在线条的开始和结束都被忽略(修剪).-使用
printf的,而不是echo以避免印刷空行当线由单一的-e,-n或者-E.但是有一种解决方法,通过使用env POSIXLY_CORRECT=1 echo "$line"它来执行支持它的外部 GNUecho.请参阅:如何回显"-e"?
请参阅:如何在没有传递参数时读取stdin?在stackoverflow SE
Ami*_*ler 18
我认为这是直截了当的方式:
$ cat reader.sh
#!/bin/bash
while read line; do
echo "reading: ${line}"
done < /dev/stdin
Run Code Online (Sandbox Code Playgroud)
-
$ cat writer.sh
#!/bin/bash
for i in {0..5}; do
echo "line ${i}"
done
Run Code Online (Sandbox Code Playgroud)
-
$ ./writer.sh | ./reader.sh
reading: line 0
reading: line 1
reading: line 2
reading: line 3
reading: line 4
reading: line 5
Run Code Online (Sandbox Code Playgroud)
Dav*_*her 13
echo每当IFS打破输入流时,解决方案都会添加新行.@fgm的答案可以修改一下:
cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}"
Run Code Online (Sandbox Code Playgroud)
问题中的Perl循环从命令行上的所有文件名参数读取,如果没有指定文件,则从标准输入读取.如果没有指定文件,我看到的答案似乎都处理单个文件或标准输入.
虽然经常被嘲笑为UUOC(无用的使用cat),但有时候cat这是工作的最佳工具,可以说这是其中之一:
cat "$@" |
while read -r line
do
echo "$line"
done
Run Code Online (Sandbox Code Playgroud)
唯一的缺点是它创建了一个在子shell中运行的管道,因此while在管道外部无法访问循环中的变量赋值.解决这个问题的bash方法是流程替换:
while read -r line
do
echo "$line"
done < <(cat "$@")
Run Code Online (Sandbox Code Playgroud)
这使得while循环在主shell中运行,因此循环中设置的变量可以在循环外部访问.
Perl 的行为,OP 中给出的代码可以不带参数,也可以带多个参数,如果参数是单个连字符,则将其-理解为标准输入。此外,文件名总是可以带有$ARGV. 迄今为止给出的答案都没有真正模仿 Perl 在这些方面的行为。这是一个纯粹的 Bash 可能性。诀窍是exec适当地使用。
#!/bin/bash
(($#)) || set -- -
while (($#)); do
{ [[ $1 = - ]] || exec < "$1"; } &&
while read -r; do
printf '%s\n' "$REPLY"
done
shift
done
Run Code Online (Sandbox Code Playgroud)
文件名在$1.
如果没有给出参数,我们人为地设置-为第一个位置参数。然后我们循环参数。如果参数不是-,我们使用 重定向来自文件名的标准输入exec。如果此重定向成功,我们将循环while循环。我正在使用标准REPLY变量,在这种情况下,您不需要 reset IFS。如果你想要另一个名字,你必须IFS像这样重置(当然,除非你不想要那个并且知道你在做什么):
while IFS= read -r line; do
printf '%s\n' "$line"
done
Run Code Online (Sandbox Code Playgroud)