没有参数传递时如何读取stdin?

时间:2013-10-27 14:59:46

标签: bash stdin

当我想在没有传递参数(文件)时使用标准输入时,脚本不起作用。有没有办法在这段代码中使用stdin而不是文件?

我试过了:

if [ ! -n $1 ] # check if argument exists
   then
   $1=$(</dev/stdin)  # if not use stdin as an argument
   fi

var="$1"
while read line
   do
   ...                # find the longest line
   done <"$var"

5 个答案:

答案 0 :(得分:10)

对于想要在缺少参数时从stdin读取值的一般情况,这将起作用。

$ echo param | script.sh
$ script.sh param

<强> script.sh

#!/bin/bash

set -- "${1:-$(</dev/stdin)}" "${@:2}"

echo $1

答案 1 :(得分:7)

只需将bash特别解释的/dev/stdin替换为文件名:

VAR=$1
while read blah; do
  ...
done < "${VAR:-/dev/stdin}"

(请注意,bash实际上会使用那个特殊的文件 /dev/stdin if built for an OS that offers it,但是因为bash 2.04可以解决该文件在不支持它的系统上的缺席。)

答案 2 :(得分:2)

pilcrow's answer提供了一个优雅的解决方案;这是对为什么OP的方法不起作用的解释。

OP方法的主要问题尝试使用{分配位置参数$1 {1}},它不会起作用。

LHS通过shell扩展为$1=...结果被解释为要分配的变量的名称 - 清楚而不是意图。

在bash中分配给$1的唯一方法是通过$1内置。 需要注意的是set总是设置所有位置参数,因此如果有的话,你还必须包含其他

set

(如果您只希望最多 1 参数,set -- "${1:-/dev/stdin}" "${@:2}" # "${@:2}" expands to all remaining parameters 会这样做。)

上述内容还纠正了OP方法的第二个问题:尝试在{中存储内容而不是stdin的 filename {1}},因为使用了set -- "${1:-/dev/stdin}"

$1是bash parameter expansion的一个应用程序,它表示:返回<的值,除非${1:-/dev/stdin}未定义(未传递任何参数)或其值为空字符串($1$1已通过)。如果"" 未定义(如果它包含 any ,则变体''(无${1-/dev/stdin})只会返回:值,即使是空字符串,也会被返回)。

如果我们把它们放在一起:

/dev/stdin

但是,当然,更简单的方法是直接使用$1作为文件名:

# Default to filename '/dev/stdin' (stdin), if none was specified.
set -- "${1:-/dev/stdin}" "${@:2}"

while read -r line; do
   ...                # find the longest line
done < "$1"

或通过中间变量:

${1:-/dev/stdin}

答案 3 :(得分:1)

变量按Var=Value分配一个值,该变量由例如echo $Var使用。 1=$(</dev/stdin) 。在你的情况下,这相当于

{{1}}

分配标准输入时。但是,我不认为允许变量名以数字字符开头。有关解决此问题的方法,请参阅问题bash read from file or stdin

答案 4 :(得分:1)

这是我的脚本版本:

#!/bin/bash
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
  printf '%s\n' "$line"
done < <(cat -- "$file")

如果参数中没有文件,请阅读标准输入

在stackoverflow SE中查看更多示例:How to read from file or stdin in bash?