在没有错误跳过的情况下评估bash函数参数
在Bash脚本中,我想创建一个包装命令的函数,在执行命令之前打印命令 因此,在这样的脚本命令中:在没有错误跳过的情况下评估bash函数参数,bash,Bash,在Bash脚本中,我想创建一个包装命令的函数,在执行命令之前打印命令 因此,在这样的脚本命令中: mkdir -p "~/new/dir/tree/" rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/" run mkdir -p "~/new/dir/tree/" run rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/" 我可以像这样在其他人面前发出命令: mkdir -p "~/n
mkdir -p "~/new/dir/tree/"
rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/"
run mkdir -p "~/new/dir/tree/"
run rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/"
我可以像这样在其他人面前发出命令:
mkdir -p "~/new/dir/tree/"
rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/"
run mkdir -p "~/new/dir/tree/"
run rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/"
我将函数的运行定义为:
run (){
echo -e "FANCY FORMATING CMD> $@ FANCY FORMAT ENDING"
eval "$@"
return $?
}
它在大多数情况下都能正常工作。当我需要在run前面使用该命令时,无论您是删除run部分还是取消设置run,它都应该可以使用或不使用该命令。我的意思是,这三个命令的工作方式应该完全相同:
run original_comand arg1 "arg2 subarg2" etc;
unset run;
run original_comand arg1 "arg2 subarg2" etc;
original_comand arg1 "arg2 subarg2" etc;
但如果我试着用这句话:
run rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/"
-e参数变为不带引号,并且实际运行的命令是
run rsync -e ssh -p 22 -av src/ user@${HOST}:dest/
如果我对-e参数的引号进行转义,它可能与run命令一起工作,但没有它就无法工作
据我从Bash文档中了解,$@应该可以工作,但很明显我在这里遗漏了一些东西。通过调用函数,您的参数不是不带引号的。将它们放在一个字符串中,并重复该字符串,从而将它们取消引号。引号不是参数的一部分,而是shell中防止分词的特殊字符,如果是单引号,则是变量扩展 shell进行单词拆分,引号保护不受影响,然后删除引号。这意味着引号将被删除,是的,但参数不会在引号中的空格上拆分 在 实用程序不会将bc作为第二个参数,但bc不是b和c,而是bc。这同样适用于您的函数 这表明您仍然可以在函数中获得正确分隔的参数:
#!/bin/sh
run () {
printf 'Arg: %s\n' "$@"
}
HOST=example.com
run mkdir -p "~/new/dir/tree/"
echo '---'
run rsync -e 'ssh -p 22' -av "src/" "user@${HOST}:dest/"
这就产生了
Arg: mkdir
Arg: -p
Arg: ~/new/dir/tree/
---
Arg: rsync
Arg: -e
Arg: ssh -p 22
Arg: -av
Arg: src/
Arg: user@example.com:dest/
正如您所看到的,ssh-P22仍然作为一个单独的参数传递给printf,而不是三个参数
在函数中执行eval$@将做正确的事情。转义引号肯定不会做正确的事情,因为它会在实际参数mkdir\dir\中包含引号,将创建一个名为dir的目录,包括引号,并且rsync-e\ssh-p22\将以-e,ssh,-p,22的形式传递给rsync
另外,请注意,~没有展开,因为它在双引号中。改为使用$HOME。传递给run的参数在传递给run时已经经历了各种扩展,并且已经正确定位,因此不需要eval来调用$1中的命令。事实上,在这种情况下使用eval是一个错误,它错误地应用了扩展和分词,而这又是一个错误,从您收到的大量错误消息可以看出
调用$1中的命令并将$@中的所有参数传递给它(第一个参数除外,即${@:2})的正确方法是,只需将$@放在一行上,而不使用eval。为什么不使用bash-x./your_script.sh?事实上,与PS4=$FANCY FORMATTING CMD一起,set-x提供了一个非常好的解决方案。要正确引用这类内容是出了名的困难。您应该在不使用eval的情况下执行$@而不是eval$@操作。它将在$1中执行命令,并将参数${@:2}传递给它。。。将在当前目录中创建一个名为~的子目录,该子目录不以引号展开。使用$HOME代替。@Robin479使用$@代替eval$@现在似乎是适合我的解决方案。我要测试一下,检查一下。谢谢