如何从stdin设置bash脚本的位置参数?

Suk*_*ima 1 bash

我有一个bash脚本,希望从文件中读取它以设置其参数。基本上我的脚本读取参数位置上($1,$2,$3等)

while test $# -gt 0; do
  case $1 in
    -h | --help)
      echo "Help cruft"
      exit 0
      ;;
  esac
  shift
done
Run Code Online (Sandbox Code Playgroud)

我希望的选项之一可能是一个读取自变量的配置文件(用于简单和简单的config),因此我希望该set --命令可以工作(--超越自变量)。但是,由于它们是在文件中定义的,因此我必须读入文件并使用xargs它们来传递它们:

-c | --config)
  cat $2 | xargs set --
  continue
  ;;
Run Code Online (Sandbox Code Playgroud)

麻烦的是xargs困扰了--我,所以我不知道该怎么做。

注意:我意识到我可以使用source config_file并将其设置为变量;可能是最终的选择。我想知道是否可以像上面那样做并简化文档。

简化的示例脚本:

# foo.sh
echo "x y z" | xargs set --
echo $*

# Command line
$ bash foo.sh a b c
xargs: set: No such file or directory
a b c
Run Code Online (Sandbox Code Playgroud)

ric*_*ici 5

xargs无法执行,set因为:

  1. set是内置的Shell,而不是外部命令。xargs只知道如何执行命令。(有些shell内置阴影具有相同名称的命令,例如printf,true和[,因此xargs可以执行这些命令,但语义可能不等同于内置的。)

  2. 即使xargs可以执行set,也不会生效,因为xargs它不会在Shell环境中运行;执行的每个命令xargs都是一个单独的过程。因此,如果您执行以下操作,则不会出错:

    echo a b c | xargs bash -c 'set -- "${@}"' _
    
    Run Code Online (Sandbox Code Playgroud)

    但这也无济于事。(用替换set,echo您将看到它确实调用了该命令。)


如何从文件中读取参数。

首先,您需要回答以下问题:在文件中包含参数意味着什么?它们是否是用空格分隔的单个单词,没有在任何参数中包含空格的机制?(这也是xargs在默认模式下工作所必需的,因此这并不是一个完全不合理的假设,尽管几乎肯定会在某个时候使您陷入困境。)

在这种情况下,您根本不需要xargs。您可以只使用命令替换:

set -- $(<file)
Run Code Online (Sandbox Code Playgroud)

尽管这样可以正常工作,但这不会:

echo a b c | set -- $(</dev/stdin)
Run Code Online (Sandbox Code Playgroud)

因为管道(由|操作员创建)使任一侧的进程都在子Shell中运行,因此set不会修改当前Shell的环境变量。


更强大的解决方案

假设每个参数都在文件的一行中,这使得可以在参数中包含空格,但不能在换行中包含空格。然后,我们可以使用有用的mapfile内置方法将参数读取到数组中,并从数组中设置位置参数。(或者直接使用数组,但这是一个不同的问题。)

mapfile -t args < file
set -- "${args[@]}"
Run Code Online (Sandbox Code Playgroud)

再次注意提防管道mapfile;由于无法使用的相同原因,它不起作用set。