我正在运行这种代码:
#!/usr/bin/env bash
set -u
exclude1='--exclude=/path/*'
exclude2='--exclude=/path with spaces/*'
exclude3='' # any 'exclude' can be empty
tar -czf backup.tgz "$exclude1" "$exclude2" "$exclude3" 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...
当我运行此代码时,我收到此错误:
tar: : Cannot stat: No such file or directory
这是因为“$exclude3”被翻译为空参数。就像我这样做一样:
tar -czf backup.tgz "$exclude1" "$exclude2" ''
避免此错误的一种方法是删除 $excludeX 周围的双引号。但如果 $excludeX 包含任何空格或其他奇怪的字符,这就会出现问题。
另一种方法是使用eval
but 因为我需要保留双引号,所以我不知道如何在需要时抑制引号和空参数。
我找到的唯一解决方案是使用字符串连接构造命令行:
CMD='tar -czf backup.tgz'
if [[ -n "$exclude1" ]]; then CMD+=" \"$exclude1\" "; fi
if [[ -n "$exclude2" ]]; then CMD+=" \"$exclude2\" "; fi
if [[ -n "$exclude3" ]]; then CMD+=" \"$exclude3\" "; fi
eval $CMD 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...
有人有更聪明的主意吗?
答案1
tar -czf backup.tgz "$exclude1" "$exclude2" ${exclude3+"$exclude3"} 2>&1
${exclude3+"$exclude3"}
如果$exclude3
未设置,则展开为空"$exclude3"
;如果设置,则展开为 。
(对于其他可能未设置的变量也类似。)
请注意,未设置的变量和设置为空字符串的变量之间存在差异,因此您应该使用
unset exclude3
代替
exclude3=''
答案2
由于您在 bash 中工作,因此请使用大批。
excludes=()
excludes+=('--exclude=/path/*')
…
tar -czf backup.tgz "${excludes[@]}"
如果某个变量中有可选条目,请将其添加到条件中。
if [[ -n $exclude_or_empty ]]; then excludes+=("$exclude_or_empty"); fi
答案3
这在 Ubuntu 上的 bash 中适用于我,但我不知道它是否符合 POSIX 标准/兼容:
tar -czf backup.tgz \
$(if "$exclude1" != ""); then echo "$exclude1"; fi
$(if "$exclude2" != ""); then echo "$exclude3"; fi
$(if "$exclude3" != ""); then echo "$exclude3"; fi