我正在编写一个备份脚本,如下所示:
backup.sh :
dir="$1"
mode="$2"
delta="$3"
for file in "$dir/backup."*".$mode.tar.gz"; do
[ "$file" -nt "$ref" ] && ref="$file"
done
if [ "$delta" = "true" ]; then
delta_cmd=-N "'$ref'"
fi
backup_file="$dir/backup.$(date +%Y%m%d-%H%M%S).$mode.tar.gz"
case "$mode" in
config)
tar -cpzvf "$backup_file" $delta_cmd \
/etc \
/usr/local
;;
# still other modes here...
esac
我想将单个变量$delta_cmd
传递给tar命令,以便它自上次备份以来只包含所有文件或delta文件,具体取决于$delta
的值。
如果$delta
设置为true,上面的代码会创建一条错误消息并且不会正确地对增量文件进行tar。如何解决?
P.S:脚本最好与POSIX兼容。
答案 0 :(得分:1)
您应该使用BASH数组来存储部分/完整命令行:
#!/bin/bash
DIR=/home/sysop/backup
mode=main
delta=false
REF=$(ls -t "$DIR"/system.*.$mode.tar.gz "$DIR"/system.*.$mode-delta.tar.gz 2>/dev/null | head -n 1)
REF=$(readlink -f "$REF")
if [ "$delta" = true ]; then
delta_cmd=(-N "$REF")
delta_suffix=("-delta")
fi
target_file="$DIR/system.$(date +%Y%m%d-%H%M%S).$mode$delta_suffix.tar.gz"
tar -cpzvf "$target_file" "${delta_cmd[@]}" \
/etc \
/usr/local \
/var/log \
/var/spool \
/home/*/logs
我还建议避免在脚本中解析ls
命令的输出。
答案 1 :(得分:1)
作为符合POSIX标准的方法,请考虑:
set -- # clear $@
if [ -f "$ref" ]; then
set -- "$@" -N "$ref" # add -N "$ref" to $@
fi
tar ... "$@" ... # expand $@ into command line
要将所有内容放在上下文中,并保护主参数列表不被覆盖,可能看起来像:
#!/bin/sh
main() {
# if current shell supports "local", prevent variables from leaking
# ...some "POSIX" shells, such as ash, will be fine with this.
local dir mode delta target_file backup_file 2>&1 ||:
dir=$1
mode=$2
delta=$3
set -- # clear $@
for file in "$dir/backup."*".$mode.tar.gz"; do
[ "$file" -nt "$ref" ] && ref="$file"
done
if [ "$delta" = "true" ]; then
set -- "$@" -N "$ref"
fi
target_file="$dir/backup.$(date +%Y%m%d-%H%M%S).$mode.tar.gz"
case "$mode" in
config)
tar -cpzvf "$target_file" "$@" \
/etc \
/usr/local
;;
# still other modes here...
esac
}
main "$@"