0

私は複数のkey=value置換を実行する関数に取り組んでいますsed:

batch_sub () {
    local file="${@: -1}" # Last argument is file to be changed.
    [[ -w "${file}" ]] || { echo "Invalid file: ${file}" ; return 1 ; }
    for arg in "${@}" ; do
        [[ $arg =~ (.*)=(.*) ]] || continue
        # 'trim_str' will trim leading & trailing spaces.
        local key=$(trim_str "${BASH_REMATCH[1]}")
        local value=${BASH_REMATCH[2]}
        sed -i 's@'"\(${key}"' *=\).*@\1'"${value}"'@' "${file}"
    done
}

この関数は、次のような引数を受け入れます。

batch_sub "a = x" "b = y" "c = z" "a.b.d.e=udp://b:8080" "/tmp/file"

そして正常に動作します。しかし、私が望むのは、次のような引数を受け入れるようにすることです:

batch_sub "a = x b = y c = z a.b.d.e=udp://b:8080" "/tmp/file"

さらに、sedこの関数内で が 1 回だけ呼び出されると便利です。

sed -i -e 's/$key=/\1$value/'
       -e 's/$key1=/\1$value1/'
       '/tmp/file'

お知らせ下さい。

4

2 に答える 2

3

この関数内で sed が 1 回だけ呼び出されると便利です

一度に複数の置換を使用して sed を呼び出すことができます。例えば

sed -i 's/a/b/;s/p/q/'

したがって、すべての引数から、すべての置換を含む単一の文字列を生成し、sed を一度だけ呼び出します。

しかし、私が望むのは、この
batch_sub "a = xb = yc = z abde=udp://b:8080" "/tmp/file" のような引数を受け入れるようにすることです

なんで?
「a = xb = yc = z abde=udp://b:8080」はあいまいに見えます。 少なくとも、 「a = x; b = y; c = z; abde=udp://b:8080」
のように、ペアには何らかの区切り記号を付けるようにしてください。

于 2012-10-16T10:58:51.080 に答える
1

これはおかしいかもしれません。しかし、あなたが設定した要件を使用すると、おそらくこのようなものになります:)

#!/bin/bash

declare -r self=${0##*\/}

# Left and right trim
trim_str()
{
    local tmp="${1##[[:space:]]}"
    printf "%s" "${tmp%%[[:space:]]}"
}

# Replace \ with \\, / with \/, & with \&
sed_esc_repl()
{
    local tmp="${1//\\/\\\\}"
    tmp="${tmp//\//\\/}"
    tmp="${tmp//&/\&}"
    printf "%s" "$tmp"
}

# Additional escape on search pattern
# escape *.][|
sed_esc_key()
{
    local tmp=$(sed_esc_repl "$1")
    tmp="${tmp//./\.}"
    tmp="${tmp//\*/\*}"
    tmp="${tmp//|/\|}"
    tmp="${tmp//[/\[}"
    tmp="${tmp//]/\]}"
    printf "%s" "$tmp"
}

batch_sub()
{
    local file=""
    local -a argv
    local key=
    local val=
    local sedstr=""
    local old_ifs=$IFS

    if (( $# < 2 )); then
        printf "Usage: $self \"replacement pairs\" <file>\n"
        return 1
    elif (( $# > 2 )); then
        file="${@: -1}"
        argv=( "${@:1:$(($#-1))}" ) # Everything but last arg
    else
        file="$2"
        argv=( "$1" )
    fi

    [[ -w "${file}" ]] || { printf "Invalid file: %s\n" "${file}"; return 1; }

    # Set IFS  to match space and equal sign.
    IFS='='' '
    for arg in ${argv[@]}; do
        if [[ "$key" != "" ]]; then
            sedstr+="s/\("$(sed_esc_key "$key")"\) *=.*/\1="$(sed_esc_repl "$arg")"/g;"
            key=
        else
            key="$arg"
        fi
    done
    IFS="$old_ifs"

    printf "sed string:\"%s\"\n\n" "${sedstr%%;}"

    sed -i "${sedstr%%;}" "$file"
}

# Create example / test file:
printf "\
x[a-zA-Z].*? = mixture1
x[a-zA-Z].*p? = mixture2
x = foo
b*x = fafa
a\\\\1c = moo
a.b$.d.e=zim zala bim
" > tst

batch_sub "$@"

exit $?

ieによって実行:

./keysw "x[a-zA-Z]。*p?= xb * x = ya \ 1c = \ z \ n \ 1 ab $ .de = udp&:// b:\ 8080" tst && cat tst

また

./keysw "x[a-zA-Z].*p? = x" \
        "b*x = y" \
        "a\1c = \z\n\1" \
        "a.b$.d.e=udp&://b:\8080" \
        tst && cat tst

与える;

ファイル:

x[a-zA-Z].*? = mixture1
x[a-zA-Z].*p? = mixture2
x = foo
b*x = fafa
a\1c = moo
a.b$.d.e=zim zala bim

結果:

x[a-zA-Z].*? = mixture1
x[a-zA-Z].*p?=x
x = foo
b*x=y
a\1c=\z\n\1
a.b$.d.e=udp&://b:\8080
于 2012-10-16T12:49:09.880 に答える