我想应用一个过滤器(例如 sed -e 's/OLD/NEW/g'
) 递归地为 SVN 属性值。
首先,在单个目标上,我可以执行以下操作之一:
-
svn propget --strict PROPNAME TARGET | sed -e 's/OLD/NEW/g' | svn propset PROPNAME --file=- TARGET
-
svn propset PROPNAME --file=<(svn propget --strict PROPNAME TARGET | sed -e 's/OLD/NEW/g') TARGET
-
SVN_EDITOR="sed -i -e 's/OLD/NEW/g'" svn propedit PROPNAME TARGET
-
svn propedit --editor-cmd "sed -i -e 's/OLD/NEW/g'" PROPNAME TARGET
哪一个是最好的?
我不喜欢 1 或 2 的是,即使 svn propget ... | sed ...
管道失败,svn propset
仍然会执行,可能在空 stdin上,重置属性。
另一方面,我不喜欢 3 或 4 的是整个过滤命令行应该被引用并制作成一个字符串,这有时会使引用和参数扩展变得棘手。请注意选项 -i
— 过滤命令应采用文件参数并就地编辑它,这意味着这些方法不能应用于不提供此类就地编辑功能的命令,例如 tr
甚至awk
。
是否有更好的选择,或者对其中之一有任何可能的改进?
其次,我如何递归地执行此操作 — 即在给定目标下具有指定属性 PROPNAME 的每个目标上?我不能只是将-R
添加到svn propget
,因为它会将所有内容连接成一个文本流,而svn propedit
甚至没有-R
。看来我必须做这样的事情:
svn proplist -R --only-with PROPNAME TARGET | while read target
do
# do one of the above on "$target"
done
但是svn proplist
没有这样的东西叫做 --only-with
,我无法轻松解析它的输出并仅获取具有该属性的那些目标的名称。
有什么好方法吗?
svn propget -R
的输出不容易解析,但 svn propget -v -R
的输出是,所以我决定运行它一次并解析它的输出。
首先,我尝试了进程替换>(...)
,但正如此线程中要求的那样,我无法强制执行或等待此类子进程的终止,因此输出消息一团糟,尽管它确实有效。因此,正如同一线程中回答的那样,我使用了协同进程:
#!/bin/bash
set -o errexit -o pipefail
if [ $# -le 2 ]; then
echo "usage: $0 PROPNAME TARGET COMMAND [ARGS...]" >&2
exit 1
fi
PROPNAME=$1; shift
TARGET=$1; shift
COMMAND=$1; shift
cleanup_and_wait() {
if [[ ${COPROC[1]} =~ ^[0-9]+$ ]]; then
eval "exec ${COPROC[1]}<&-"
wait $COPROC_PID
fi
}
unset curr_target
unset prev_line
while IFS= read -r line; do
case "$line" in
" "*)
line=${line:4}
if declare -p prev_line >/dev/null 2>&1; then
echo "$prev_line" >&${COPROC[1]}
fi
prev_line=$line
;;
" "*)
line=${line:2}
if [ "$line" != "$PROPNAME" ]; then
echo "Unexpected property: $line" >&2
fi
cleanup_and_wait
coproc { "$COMMAND" "$@" | svn propset "$PROPNAME" --file=- "$curr_target"; } >&2
unset prev_line
;;
"Properties on '"*"':")
line=${line%"':"}
line=${line#"Properties on '"}
curr_target=$line
;;
esac
done < <(svn propget --verbose --recursive "$PROPNAME" "$TARGET")
cleanup_and_wait
我不喜欢的一件小事是,即使给定的过滤器不更改属性值,svn propset
仍然执行并打印property 'PROPNAME' set on 'TARGET'
;很高兴只看到那些属性值实际更改的目标的消息。