我的意思是用来rsync
删除某些文件(例如高效删除包含数千个文件的大型目录),在本例中将其作为命令行中的模式赋予 shell 脚本。
到目前为止,这就是我的 shell 脚本中的内容rsync_del.sh
#!/bin/bash
TARGET_DIR=${1}
shift
PATTERNS="${@}"
for patt in ${PATTERNS} ; do
# Both do the same
#INCLUDE_PATTERNS="${INCLUDE_PATTERNS}"' --include='\'"${patt}"\'
INCLUDE_PATTERNS="${INCLUDE_PATTERNS} --include=\"${pattern}\""
done
EMPTYDIR=$(mktemp -d)
echo "Created empty dir ${EMPTYDIR}"
comm="rsync -a --progress --delete ${INCLUDE_PATTERNS} ${EMPTYDIR}/ ${TARGET_DIR}"
echo ${comm}
eval ${comm}
我想使用的示例模式是*[1-9].txt
, *000??9.txt
。问题是,执行时
rsync_del.sh trg_dir '*[1-9].txt'
生成的命令行是
rsync -a --progress --delete --include='*[1-9].txt' /tmp/tmp.51R9hPgkfG/ trg_dir/
(这对我来说似乎没问题),但它是匹配的,例如,类似的文件input.dat
(我不想要这样)。
实施/使用这个的正确方法是什么? 我怀疑这是一个正确转义模式的问题,但我无法做到这一点。
echo
注意:我需要在执行之前在变量中定义要执行的命令。
答案1
没有太仔细地观察实际情况使用在rsync
这里,而不是专注于命令行的创建rsync
。
#!/bin/bash
target=$1
shift
empty=$( mktemp -d )
trap 'rmdir "$empty"' EXIT
for pattern do
incl+=( --include="$pattern" )
done
rsync --archive --progress --delete "${incl[@]}" --exclude='*' "$empty"/ "$target"
通过使用数组(incl
上面的数组),您可以单独存储参数rsync
,而不是像字符串那样。的扩展"${incl[@]}"
将是数组中单独引用的元素。引用参数变得微不足道,无需调用eval
.另请注意,所有参数扩展都需要正确加双引号。
您的代码的问题在于您使用了大多数未加引号的参数扩展。这使得 shell 对变量执行分词和文件名生成(通配)。这又意味着您不能使用包含空格的模式或可能扩展到现有文件名称的 shell 通配模式。
因为/bin/sh
语法变得更加简洁:
#!/bin/sh
target=$1
shift
empty=$( mktemp -d )
trap 'rmdir "$empty"' EXIT
for pattern do
set -- "$@" --include="$pattern"
shift
done
rsync --archive --progress --delete "$@" --exclude='*' "$empty"/ "$target"
答案2
我忘记了我应该通过排除任何未明确包含的内容来关闭模式列表。我用了
comm="rsync -a --progress --delete ${INCLUDE_PATTERNS} --exclude=\"*\" ${EMPTYDIR}/ ${TARGET_DIR}"