bash - определить подстроку в одной переменной, когда связанная подстрока известна в другой переменной - PullRequest
2 голосов
/ 29 сентября 2011

Предполагая, что у меня было две строки, одна действует как строка ключей, разделенных пробелом, а другая действует как ассоциативные значения, разделенные пробелом, для каждого из ключей в первой:

KEYS="key_1 key_2 key_3"
VALS="value1 aDifferentValue_2 theFinalValue"

Таким образом, в этом случае key_1 в $KEYS имеет ассоциированное значение value1, key_2 имеет ассоциированное значение aDifferentValue_2 и т. Д. Скажем, рассматриваемый ключ был key_2, хранящийся в переменной $FIELD, как проще всего использовать sed и / или awk, чтобы выяснить, что, исходя из положения слова, значение должно быть aDifferentValue_2? Есть ли способ создать ассоциативный массив, используя подстроки $KEYS в качестве ключей и $VALS в качестве значений?

Ответы [ 6 ]

2 голосов
/ 29 сентября 2011

Поскольку это тег bash, у вас могут быть фактические ассоциативные массивы (bash v4):

KEYS="key_1 key_2 key_3"
VALS="value1 aDifferentValue_2 theFinalValue"
keys=( $KEYS )
vals=( $VALS )
declare -A map
for (( i=0; i<${#keys[@]}; i++ )); do
  map["${keys[$i]}"]="${vals[$i]}"
done
for idx in "${!map[@]}"; do
  echo "$idx -> ${map[$idx]}"
done

выходы

key_1 -> value1
key_2 -> aDifferentValue_2
key_3 -> theFinalValue

Если у вас нет bash v4, вы все равно можете использовать индексированные массивы keys и vals и:

get_key_idx() {
  for (( i=0; i<${#keys[@]}; i++ )); do 
    if [[ "$key" = "${keys[$i]}" ]]; then
      echo $i
      return 0
    fi
  done
  return 1
}

key="key_2"
if idx=$(get_key_idx $key); then
  echo "$key -> ${vals[$idx]}"
else
  echo "no mapping for $key"
fi
1 голос
/ 29 сентября 2011

Чистая оболочка POSIX:

#!/bin/sh

# set -x

assoc() {
  keys="$1 "
  values="$2 "
  key=$3
  while [ -n "$keys" -a -n "$values" ]; do
    key_=${keys%% *}
    keys=${keys#* }
    value_=${values%% *}
    values=${values#* }
    if [ $key_ = $key ]; then
      echo $value_
      return 0
    fi
  done
  return 1
}

keys='a b c'
values='1 2 3'
key=b
echo Value for key $key is _`assoc "$keys" "$values" "$key"`_

keys='a b c'
values='1 2 3'
key=xxx
echo Value for key $key is _`assoc "$keys" "$values" "$key"`_

keys='a b c'
values='1 2 3 4 5'
key=c
echo Value for key $key is _`assoc "$keys" "$values" "$key"`_

keys='a b c'
values='1 2'
key=c
echo Value for key $key is _`assoc "$keys" "$values" "$key"`_

При запуске:

  bash# ./1.sh   
Value for key b is _2_
Value for key xxx is __
Value for key c is _3_
Value for key c is __
1 голос
/ 29 сентября 2011

как насчет:

Переменные:

/home/sirch>KEYS="key_1 key_2 key_3"
/home/sirch>VALS="value1 aDifferentValue_2 theFinalValue"

Код:

/home/sirch>cat s.awk
BEGIN{
    split(keystring,key," ");
    split(valstring,temp," ")
    for(i=1;i<=length(key);i++)val[key[i]]=temp[i]
}
END{print val["key_2"]}

Выход:

/home/sirch>awk -v "keystring=$KEYS" -v "valstring=$VALS" -v "query=key_02" -f s.awk f
aDifferentValue_2

Сначала устанавливаются переменные оболочки KEYS и VALS. Затем они экспортируются в akw в виде строк. Эти строки затем разделяются на пробелы, полученные массивы сохраняются в «ключ» и «темп». temp используется для создания хеш-карты vinal "val". Теперь вы можете запросить val ["key_1"] и т. Д., Чтобы получить соответствующее значение из строки оболочки VALS.

Чтобы запустить это из сценария оболочки, просто сохраните сценарий awk в файл. Затем установите запрос переменной оболочки в строку запроса и вызовите awk-скрипт из скрипта оболочки с этой переменной. Вам нужно будет дать фиктивный файл, здесь "f", в качестве аргумента для awk, чтобы эта работа работала.

HTH Крис

0 голосов
/ 30 сентября 2011

Вот решение sed:

keys="key_1 key_2 key_3" values="value_1 value_2 value_3" key="key_2" # variables used

str="$keys @@$values $key " # keys/values delimit by '@@' add key N.B. space after key!

sed -rn ':a;s/^(\S* )(.*@@)(\S* )(.*)/\2\4\1\3/;ta;s/^@@(\S* ).*\1(\S*).*/\2/p' <<<"$str"

# re-arrange keys/values into a lookup table then match on key using back reference
0 голосов
/ 30 сентября 2011

другое решение AWK (может быть, короче?)

echo "$keys $vals"|awk '{t=NF/2;for(i=1;i<=t;i++)a[$i]=$(i+t);}{print a[KeyYouWANT]}'

test:

kent$  keys="key_1 key_2 key_3"    
kent$  vals="value1 aDifferentValue_2 theFinalValue"
kent$  echo "$keys $vals"|awk '{t=NF/2;for(i=1;i<=t;i++)a[$i]=$(i+t);} END{print a["key_2"]}'  

aDifferentValue_2

Вы также можете поместить желаемый keyStr в переменную

kent$  want=key_3
kent$  echo "$keys $vals"|awk -v x=$want '{t=NF/2;for(i=1;i<=t;i++)a[$i]=$(i+t);} END{print a[x]}'   

theFinalValue

или вы хотите увидеть полный список:

kent$  echo "$keys $vals"|awk '{t=NF/2;for(i=1;i<=t;i++)a[$i]=$(i+t);} END{for(x in a)print x,a[x]}'

key_1 value1
key_2 aDifferentValue_2
key_3 theFinalValue
0 голосов
/ 29 сентября 2011

Вот альтернатива только для bash:

#!/bin/bash -x

KEYS="key_1 key_2 key_3"
VALS="value1 aDifferentValue_2 theFinalValue"

assoc() {
    read fkey rkeys
    read fval rvals
    if [ "X$fkey" == "X$1" ] ; then echo $fval; exit 0; fi
    if [ "X$rkeys" == "X" ] ; then exit 1; fi
    echo -e "$rkeys\n$rvals" | assoc $1
}

echo -e "$KEYS\n$VALS" | assoc key_2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...