使用stdin作为变量的bash

时间:2016-01-05 11:40:59

标签: bash shell unix

我希望确保我的脚本在用户使用如下语法时能够正常工作:

script.sh firstVariable < SecondVariable

出于某种原因,我无法让它发挥作用。

我想$ 1 = firstVariable 并且$ 2 = SecondVariable

但由于某些原因,我的脚本认为只存在firstVariable?

2 个答案:

答案 0 :(得分:3)

这是一个经典的X-Y problem。目标是编写一个实用程序

utility file1 file2

utility file1 < file2

具有相同的行为。似乎很有诱惑力找到一种方法以某种方式将第二次调用转换为第一次调用(通过某种方式)找出&#34; name&#34; stdin,然后使用与第二个参数相同的方式使用该名称。不幸的是,这是不可能的。重定向发生在调用该实用程序之前,并且没有可移植的方法来获取&#34; name&#34;一个打开的文件描述符。 (事实上​​,在other_cmd | utility file1的情况下,它甚至可能没有名称。)

因此,解决方案是关注所要求的内容:使两种行为保持一致。大多数标准实用程序都是这种情况(grepcatsort等):如果未指定输入文件,该实用程序将使用stdin

在许多unix实现中,stdin确实有一个名称:/dev/stdin。在这样的系统中,可以通过以下方式实现上述目的:

utility() {
  utility_implementation "$1" "${2:-/dev/stdin}"
}

其中utility_implementation实际上做了所需的事情。第二个参数的语法是普通默认值parameter expansion;如果$2存在且非空,则表示$2的值,否则表示字符串/dev/stdin。 (如果你遗漏了-以便它是&#34; $ {2:/ dev / stdin}&#34;,那么如果$2stdin则它不会进行替换现在和空,这可能会更好。)

解决问题的另一种方法是确保第一种语法与第二种语法相同,这样即使使用命名文件,输入总是来自utility() { if (( $# < 2 )); then utility_implementation "$1" else utility_implementation "$1" < "$2" fi } 。显而易见的简单方法:

exec

另一种方法是使用stdin命令只需重定向来重定向shell自己的(。请注意,我们必须在子shell() ... {而不是} ... utility() ( if (( $# > 1 )) then; exec < "$2"; fi # implementation goes here. $1 is file1 and stdin # is now redirected to $2 if $2 was provided. # ... ) )内执行此操作,以便重定向不适用于shell它调用函数:

{{1}}

答案 1 :(得分:1)

使第二个变量的stdin成为脚本的最后一个参数(所以如果你有一个arg然后&lt; second arg,它将是第二个),你可以使用下面的

#!/bin/bash

##read loop to read in stdin
while read -r line
do

  ## This just checks if the variable is empty, so a newline isn't appended on the front
  [[ -z $Vars ]] && Vars="$line" && continue

  ## Appends every line read to variable
  Vars="$Vars"$'\n'"$line"

  ## While read loop using stdin
done < /dev/stdin

 ##Set re-sets the arguments to the script to the original arguments and then the new argument we derived from stdin
set - "$@" "$Vars"

## Echo the new arguments
echo "$@"