如何在Bash管道(cat/wget | bash)中传递脚本参数
这个问题我太熟了!管道执行脚本(比如cat script.sh | bash或者wget ... | bash)和直接执行脚本的参数传递逻辑确实不一样——直接执行时参数是传给脚本本身的,但管道模式下bash是从标准输入读脚本内容,默认不会把命令行参数递交给脚本。不过用bash -s选项就能完美解决,这也是nvm安装脚本采用的核心方法。
核心解法:用bash -s让参数流向脚本
当你通过管道把脚本内容传给bash时,加上-s选项,bash就会把后续的命令行参数当成脚本的位置参数(也就是$1、$2这类变量),而不是bash自身的命令选项。
拿你的test.sh举例子:
#!/usr/bin/env bash echo $1 echo "execution done"
原来的管道执行方式cat test.sh | bash "started"会失败,因为"started"会被bash当成要执行的文件名,而非脚本参数。改成下面的命令就完全正常了:
cat test.sh | bash -s "started"
执行后输出和直接执行一致:
started execution done
处理带-开头的特殊参数
如果你的参数是以-开头的(比如-v、--help),为了避免bash把它们误判成自身的命令选项,需要用--来分隔bash选项和脚本参数:
cat test.sh | bash -s -- -v
这样脚本里的$1就能准确拿到-v,不会被bash拦截。
结合bash自身选项的场景
如果需要给bash加自身的选项(比如-x开启调试模式),把bash的选项放在-s前面即可:
cat test.sh | bash -x -s "started"
这样bash会先开启调试输出,同时把"started"正常传给脚本作为$1。
多参数传递
传递多个参数也很简单,直接在-s后面依次列出就行:
cat test.sh | bash -s "first arg" "second arg"
脚本里的$1会是first arg,$2会是second arg,和直接执行脚本的参数逻辑完全一致。
为什么nvm安装脚本这么写?
nvm的安装命令(比如curl ... | bash -s -- --version)就是用了这个逻辑:-s告诉bash从标准输入读取安装脚本,--用来明确分隔bash选项和脚本参数,后面的--version就是传给安装脚本的指令,让脚本执行特定的版本查询逻辑。
内容的提问来源于stack exchange,提问作者Vipin

