1

我想sed -e 's/OLD/NEW/g'递归地对 svn 属性值应用过滤器(例如)。

首先,在单个目标上,我可以执行以下操作之一:

  1. svn propget --strict PROPNAME TARGET | sed -e 's/OLD/NEW/g' | svn propset PROPNAME --file=- TARGET
  2. svn propset PROPNAME --file=<(svn propget --strict PROPNAME TARGET | sed -e 's/OLD/NEW/g') TARGET
  3. SVN_EDITOR="sed -i -e 's/OLD/NEW/g'" svn propedit PROPNAME TARGET
  4. svn propedit --editor-cmd "sed -i -e 's/OLD/NEW/g'" PROPNAME TARGET

哪一个是最好的?

我不喜欢 1 或 2 的是,即使svn propget ... | sed ...管道失败,svn propset仍会执行,可能在空的标准输入上,重置属性。

另一方面,我不喜欢 3 或 4 的地方是整个过滤命令行应该被引用并制成一个字符串,这有时会使引用和参数扩展变得棘手。并注意选项-i- 过滤命令应该采用文件参数并就地编辑它,这意味着这些方法不能应用于不提供这种就地编辑功能的命令,例如tr甚至awk.

有没有更好的选择,或者对其中之一有任何可能的改进?

其次,我如何递归地执行此操作 - 即在给定 TARGET 下具有指定属性 PROPNAME 的每个目标上?我不能只添加-Rsvn 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,我不能轻易地解析它的输出并只获取那些具有该属性的目标的名称。

有什么好的方法吗?

4

1 回答 1

1

的输出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';最好只看到那些属性值实际发生变化的目标的消息。

于 2012-06-21T20:17:43.290 回答