如何从标准输入设置 bash 脚本的位置参数?
How do I set a bash script's positional arguments from stdin?
我有一个 bash 脚本,我希望从文件中读取该脚本以获取其参数集。基本上我的脚本按位置读取参数(
、
、
等)
while test $# -gt 0; do
case in
-h | --help)
echo "Help cruft"
exit 0
;;
esac
shift
done
我希望的选项之一可以是读取参数的配置文件(为了简单易行 config)所以我希望 set --
命令可以工作(--
超越争论)。但是,由于它们是在文件中定义的,所以我必须读入它并使用 xargs
来传递它们:
-c | --config)
cat | xargs set --
continue
;;
问题是 xargs 干扰了 --
所以我不知道如何完成它。
注意:我知道我可以使用 source config_file
并设置变量;可能是最后的选择。我想知道我是否可以像上面那样做并简化 documentation.
一个简化的示例脚本:
# 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
xargs
无法执行 set
因为:
set
是 shell 内置命令,不是外部命令。 xargs
只会执行命令。 (一些shell内置的同名shadow命令,如printf
、true
、[
。所以xargs
可以执行这些命令,但是语义可能与内置语义不同。)
即使xargs
可以执行set
,也没有效果,因为xargs
不会运行在[=68=里面]的环境; xargs
执行的每个命令都是一个单独的进程。所以如果你这样做你不会得到错误:
echo a b c | xargs bash -c 'set -- "${@}"' _
但它也不会做任何有用的事情。 (将 set
替换为 echo
,您会发现它确实调用了命令。)
如何从文件中读取参数。
首先,您需要回答这个问题:文件中有参数是什么意思?它们是单独的以空格分隔的单词,没有在任何参数中包含空格的机制吗? (这也是 xargs
在其默认模式下工作所必需的,因此这并不是一个完全不合理的假设,尽管它几乎肯定会在某些时候给您带来麻烦。)
在那种情况下,您根本不需要 xargs
;你可以只使用命令替换:
set -- $(<file)
虽然这可以正常工作,但这不会:
echo a b c | set -- $(</dev/stdin)
因为管道(由 | 运算符创建)导致任一侧的进程在子 shell 中为 运行,因此set
不修改当前 shell 的环境变量。
更强大的解决方案
假设每个参数都在文件中的一行中,这使得可以在参数中包含空格,但不能包含换行符。然后我们可以使用有用的 mapfile
内置函数将参数读入数组,并从数组中设置位置参数。 (或者直接使用数组,但那将是一个不同的问题。)
mapfile -t args < file
set -- "${args[@]}"
再次注意管道进入 mapfile
;它不起作用,原因与它不适用于 set
.
的原因相同
我有一个 bash 脚本,我希望从文件中读取该脚本以获取其参数集。基本上我的脚本按位置读取参数(、
、
等)
while test $# -gt 0; do
case in
-h | --help)
echo "Help cruft"
exit 0
;;
esac
shift
done
我希望的选项之一可以是读取参数的配置文件(为了简单易行 config)所以我希望 set --
命令可以工作(--
超越争论)。但是,由于它们是在文件中定义的,所以我必须读入它并使用 xargs
来传递它们:
-c | --config)
cat | xargs set --
continue
;;
问题是 xargs 干扰了 --
所以我不知道如何完成它。
注意:我知道我可以使用 source config_file
并设置变量;可能是最后的选择。我想知道我是否可以像上面那样做并简化 documentation.
一个简化的示例脚本:
# 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
xargs
无法执行 set
因为:
set
是 shell 内置命令,不是外部命令。xargs
只会执行命令。 (一些shell内置的同名shadow命令,如printf
、true
、[
。所以xargs
可以执行这些命令,但是语义可能与内置语义不同。)即使
xargs
可以执行set
,也没有效果,因为xargs
不会运行在[=68=里面]的环境;xargs
执行的每个命令都是一个单独的进程。所以如果你这样做你不会得到错误:echo a b c | xargs bash -c 'set -- "${@}"' _
但它也不会做任何有用的事情。 (将
set
替换为echo
,您会发现它确实调用了命令。)
如何从文件中读取参数。
首先,您需要回答这个问题:文件中有参数是什么意思?它们是单独的以空格分隔的单词,没有在任何参数中包含空格的机制吗? (这也是 xargs
在其默认模式下工作所必需的,因此这并不是一个完全不合理的假设,尽管它几乎肯定会在某些时候给您带来麻烦。)
在那种情况下,您根本不需要 xargs
;你可以只使用命令替换:
set -- $(<file)
虽然这可以正常工作,但这不会:
echo a b c | set -- $(</dev/stdin)
因为管道(由 | 运算符创建)导致任一侧的进程在子 shell 中为 运行,因此set
不修改当前 shell 的环境变量。
更强大的解决方案
假设每个参数都在文件中的一行中,这使得可以在参数中包含空格,但不能包含换行符。然后我们可以使用有用的 mapfile
内置函数将参数读入数组,并从数组中设置位置参数。 (或者直接使用数组,但那将是一个不同的问题。)
mapfile -t args < file
set -- "${args[@]}"
再次注意管道进入 mapfile
;它不起作用,原因与它不适用于 set
.