Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在没有错误跳过的情况下评估bash函数参数_Bash - Fatal编程技术网

在没有错误跳过的情况下评估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

在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 "~/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$@现在似乎是适合我的解决方案。我要测试一下,检查一下。谢谢