linux - 从终端执行命令与从脚本执行命令 - 带通配符的路径 - 防止 glob 扩展

标签 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"

最佳答案

我查看了您的问题历史记录,发现您熟悉 PHP。这是 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()?

答案当然是变量中的文字引号与函数的调用方式无关。这在 PHP 和 shell 中都是一样的。

PHP 和 Bash 中的解决方案都是使用数组:

#!/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 更原始,不支持任意数组,但我们可以重用位置参数来达到同样的效果:

#!/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" "$@"

另一种选择是使用 eval 将字符串重新解释为 shell 命令。这意味着任何可以影响您的变量的人都可以接管您的系统,但如果所有变量都来自具有同等权限的用户,这可能没问题:

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

关于linux - 从终端执行命令与从脚本执行命令 - 带通配符的路径 - 防止 glob 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43593393/

相关文章:

linux - 提供日志读取权限的方法

macos - cd 到 bash 脚本中以波浪号 (~) 开头的文件夹名称

LINUX:升级生产机器

Java 应用程序无法在 debian 中以非 root 用户身份连接到 mysql

linux - 重命名服务器 cpanel jailshell 上的文件

linux - 在每次登录到 shell 时打印 session 中最后 10 个命令的历史记录

c - 如何在 SYSTEM 下运行应用程序?

linux - gdb 不接受输入重定向

linux - 从 Apache 中的 CGI 脚本创建时,绑定(bind)挂载不可见

shell脚本: not able to assign integer to a variable