2012-10-16 39 views
0

我工作的一個函數來sed執行多個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 '[email protected]'"\(${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在這個函數中調用一次:

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

請告知。

+0

注意' 'S/$鍵=/\ $ 1值/''不會擴大,因爲單引號的變量。你可以建立在bash的數組(在bash 4的關聯數組),或者你可以使用分號混搭你的sed替代在一起。但是你一定需要一個簡潔的輸入格式。你的功能已經接受的工作正常,但你「想要」的那個不清楚。如果$ value中有等號,該怎麼辦? – ghoti

+0

是的,謝謝你的頭了,我所知道的是,那些只是僞代碼,有點懶的類型和配對所有的'「'。:) 感謝的提示」混搭在一起,你的sed使用分號」替代 而我想我會離開‘如果有在'$ value'等號’現在:) – leafei

回答

3

如果sed的這將是很好的此功能

您可以同時對多個換人打電話的sed中調用一次。 例如

SED -i 'S/A/B /; S/P/Q /'

從所有參數

所以,產生一個字符串,它涉及所有的取代&然後調用所有SED一次。

但我要的是讓它接受這樣
batch_sub參數 「A = XB = YC = Z ABDE = UDP:// B:8080」 「/ tmp目錄/文件」

爲什麼?
「a = x b = y c = z a.b.d.e = udp:// b:8080」在我看來很模棱兩可。
至少要嘗試爲某些配對使用某種分隔符,例如
「a = x; b = y; c = z; a.b.d.e = udp:// b:8080」

+0

感謝您的'sed的-i「S/A/b /中的提示; ... S/p/q /''&'「a = x; b = y; c = z; ABDE = UDP:// B:8080" ' – leafei

+0

歡迎您:-) – anishsane

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 "[email protected]" 

exit $? 

通過即執行命令?

./keysw「X [A-ZA-Z] * P = XB * X = ya \ 1c = \ z \ n \ 1 ab $ .d。E = UDP &:// B:\ 8080" TST & &貓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 
+0

是的,這是一個有點嚇人:)但仍可能我使用一些代碼的 – leafei

+0

@leafei是通過一切手段:)。?。相當模糊的文件,命令僅測試正則表達式並得到正確轉義。 – Morpfh

+0

謝謝。我的任務是很基本的,我想用'@'作爲分隔符'sed'是現在好了,要小心,雖然。 – leafei