Linux下C-shell脚本source子脚本时意外传参的原因与解决方法
这其实是C-shell中source命令的默认行为导致的:
当你使用source命令执行脚本时,脚本是在当前shell进程中运行的,而不是启动一个新的子shell。如果调用source时没有显式指定参数,C-shell会自动将当前shell的**位置参数列表(也就是$argv,对应父脚本被调用时传入的abc和def)**传递给被source的子脚本。简单来说,子脚本会继承当前shell环境里的所有位置参数,而当前shell的参数就是父脚本启动时的那些参数。
举个直观的例子:当你执行parent.csh abc def时,父脚本的$argv就是(abc, def),此时在父脚本里source child.csh,子脚本会直接复用这个$argv,所以子脚本里的$1是abc,$2是def。
有三种实用的方法可以解决这个问题,你可以根据自己的场景选择:
方法1:source时显式传入空参数列表
在父脚本调用子脚本时,直接传递一个空的参数列表,覆盖当前的位置参数:
# 在parent.csh中修改调用语句 source child.csh ()
或者用更直观的空字符串写法:
source child.csh ""
这样子脚本的$argv就会被清空,不会继承父脚本的参数。
方法2:临时保存父脚本参数,清空后再恢复
如果你在父脚本后续还需要使用原来的参数,可以先把它们临时保存起来,清空当前位置参数后再source子脚本,最后恢复参数:
# parent.csh中的修改 # 1. 保存当前参数 set saved_args = ($argv) # 2. 清空位置参数 set argv = () # 3. source子脚本 source child.csh # 4. 恢复原来的参数 set argv = ($saved_args)
这种方法适合需要保留父脚本参数继续使用的场景。
方法3:在子脚本开头主动清空参数
如果子脚本本身不需要任何参数,可以直接在子脚本的开头添加清空参数的语句,从根源上避免继承:
# child.csh的开头添加 set argv = ()
这样不管父脚本有没有传递参数,子脚本内部的位置参数都会是空的。
示例验证
假设原脚本:parent.csh:
#!/bin/csh echo "Parent args: $argv" source child.csh
child.csh:
#!/bin/csh echo "Child args: $argv"
执行./parent.csh abc def会输出:
Parent args: abc def Child args: abc def
用方法1修改后,parent.csh的调用语句改为source child.csh (),执行后输出:
Parent args: abc def Child args:
内容的提问来源于stack exchange,提问作者daveg

