从终端执行命令vs从脚本执行命令 - 带通配符的路径 - 防止全局扩展

时间:2017-04-24 16:31:06

标签: linux shell debian

我遇到一个奇怪的问题,我认为它与文件/目录通配

有关

脚本

echo "tar -zcvf $file $base/$target $exclude_args"
cd $base && tar -zcvf $file $base/$target $exclude_args

输出

tar -zcvf www_2017-04-24.tar.gz /var/www  --exclude '/var/www/bak/*/*' --exclude '/var/www/test'

运行脚本时,省略排除路径(每个目录都是gzip压缩)

直接从putty运行输出时,/var/www/bak/*/*下的目录从gzip中排除

更新

parse_exclude_paths (){
    # escape forward slashes to avoid the paths to expand
    args=$(echo "$exclude" | sed 's,/,\\\/,g')
    args=$(printf " --exclude '%s'" $args)
    # strip escapes
    echo "$args" | sed 's,\\\/,/,g'
}

exclude="/var/www/bak/*/* /var/www/test"
exclude_args=''
if [ ! -z "$exclude" ]; then
    exclude_args="$(parse_exclude_paths "$exclude")"
fi

更新2

如果通过SSH发送命令没有问题,排除路径将从gzip中排除

ssh root@$host 'cd '"$base"' && tar -zcvf $file '"$base/$target $exclude_args"

1 个答案:

答案 0 :(得分:0)

I snooped your question history and saw that you're familiar with PHP. Here's the equivalent problem in PHP:

function foo($arg1, $arg2) {
  echo "You passed $arg1 and $arg2\n";
}

$var='"one", "two"';
echo "Running: foo($var);\n";
foo($var);

The echo prints Running: foo("one", "two"); and that command works just fine if you copy-paste it!

Why does foo($var); instead write PHP Warning: Missing argument 2 for foo()?

The answer is of course that literal quotes in your variables don't matter for how the function is called. This is the same in both PHP and shell.

The solution in both PHP and Bash is to use an array:

#!/bin/bash
file="www_2017-04-24.tar.gz"
base="/var"
target="www"
exclude_args=( --exclude '/var/www/bak/*/*' )

cd "$base" && tar -zcvf "$file" "$base/$target" "${exclude_args[@]}"

sh is more primitive and doesn't support arbitrary arrays, but we can reuse the positional parameters to the same effect:

#!/bin/sh
file="www_2017-04-24.tar.gz"
base="/var"
target="www"
set -- --exclude '/var/www/bak/*/*' # Now assigned to $1, $2, etc

cd "$base" && tar -zcvf "$file" "$base/$target" "$@"

Another option is to use eval to re-interpret a string as a shell command. This means that anyone who can influence your variables can take over your system, but that may be ok if all the variables come from users with equivalent privileges:

eval "tar -zcvf $file $base/$target $exclude_args"