简体   繁体   English

在bash中查找并替换相同的字符串

[英]Find and replace in same string in bash

I have a string with some words in them, example a=1 b=2 c=3 a=50 . 我有一个带有一些单词的字符串,例如a=1 b=2 c=3 a=50 Now I want to parse this and create another string a=50 b=2 c=3 which is essentially the same as above except that if the same phrase before the = is encountered for the second time the first one is over written with the latest one, so in the end there are only unique phrases on the left of = . 现在我想解析它并创建另一个字符串a=50 b=2 c=3与上面的字符串基本相同,不同之处在于,如果第二次遇到=之前的相同短语,则第一个字符串a=50 b=2 c=3字符串覆盖一个,所以最后在=的左边只有唯一的短语。 Here is what I got till now: 这是到现在为止我得到的:

a="a=1 b=2 c=3 a=50"
o=()

for i in $a
do
    reg=${i%=*}
    if [[ ${o[*]} == *"$reg"* ]]
    then
        o=$(echo ${o[*]} | sed -e "s/\$reg=\S/\$i")
    else
        o+=( $i )
    fi
done

What am I doing wrong here? 我在这里做错了什么?

I'd take an entirely different approach, not based on regular expressions or string rewriting. 我会采用完全不同的方法, 而不是基于正则表达式或字符串重写。

declare -A values=( )              # Initialize an associative array ("hash", "map")
while IFS= read -r -d' ' word; do  # iterate over input words, separated by spaces
  if [[ $word = *=* ]]; then       # ignore any word that doesn't have an "=" in it
    values[${word%%=*}]=${word#*=} # add everything before the "=" as a key...
  fi                               # ...with everything after the "=" as a value
done

for key in "${!values[@]}"; do     # Then iterate over keys we found
  value="${values[$key]}"          # ...extract the values for each...
  printf '%s=%s ' "$key" "$value"  # ...and print the pairs.
done
echo                               # When done iterating, print a newline.

Because the words are being processed first-to-last through the string, updates take effect before the print loop is reached. 由于单词是通过字符串进行优先处理的,因此更新将在到达打印循环之前生效。

Using awk 使用awk

$ awk -F= -v RS=" |\n" '{a[$1]=$2} END{for (k in a) printf "%s=%s ",k,a[k]}' <<<"a=1 b=2 c=3 a=50"
a=50 b=2 c=3

How it works: 这个怎么运作:

  • -F=

    Set the field separator to be an equal sign. 将字段分隔符设置为等号。

  • -v RS=" |\\n"

    Set the record separator to be either a space or a newline. 将记录分隔符设置为空格或换行符。

  • a[$1]=$2

    Update associative array a with the latest value. 用最新值更新关联数组a

  • END{for (k in a) printf "%s=%s ",k,a[k]}

    In no particular order, print out the final values. 以不特定的顺序打印最终值。

Using bash 使用bash

Like Charles Duffy's approach, this uses read -d" " to parse the string. 就像Charles Duffy的方法一样,它使用read -d" "来解析字符串。 This approach, however, uses IFS="=" to separate names and values. 但是,这种方法使用IFS="="来分隔名称和值。

Two loops are required. 需要两个循环。 The first gathers the values. 第一个收集值。 The second reassembles the updated values in the original order: 第二次以原始顺序重新组合更新的值:

a="a=1 b=2 c=3 a=50"
declare -A b
while IFS== read -d" " name value
do
    b["$name"]="$value"
done <<<"$a "

declare -A seen
while IFS== read -d" " name value
do
    [ "${seen[$name]}" ] || o="$o $name=${b["$name"]}"
    seen[$name]=1
done <<<"$a "
echo "$o"

Easily done with perl: 使用perl轻松完成:

echo "a=1 b=2 c=3 a=50" \
  | sed "s/ /\n/g" \
  | perl -e '
my %hash = ();
while(<>){
  $line = $_;
  if($line =~ m/(\S+)=(\S+)/) {
    $hash{$1} = $2;
  }
}
for $key (sort keys %hash) {
  print "$key=$hash{$key}\n";
}'

...or, all on one line: ...或者全部一行:

echo "a=1 b=2 c=3 a=50" | sed "s/ /\n/g" | perl -e 'my %hash = (); while(<>){ $line = $_; if($line =~ m/(\S+)=(\S+)/) { $hash{$1} = $2; } } for $key (sort keys %hash) { print "$key=$hash{$key}\n"; }'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM