Массив в AWK требует уточнения кода

Если вы используете международную клавиатуру США(us _intl ), вы можете сделать Alt Gr + Shift + ;

1
21.05.2021, 18:36
4 ответа

Основная проблема заключается в этой строке newval=ref[val], где переменная valв качестве ключа (равна $1в val=$1), что на самом деле означает newval=ref[$1], с этой строкой newvalсодержимому переменной присваивается значение ref[val]из массива ref[], если этот ключ существовал, иначе присваивается пустое значение; делая это таким образом, т.е. newval=ref[val]если ключ не был найден в массиве, этот ключ будет добавлен в массив с пустым значением, с которым вы можете столкнуться с некоторыми проблемами в будущем, когда вы не хотите, чтобы размер/индексы вашего массива изменялись или он может превысить доступную память или значительно замедлить работу сценария, если этот файл огромен.

... тогда в операторе if -else, и вы тестируете newval, всегда выполняется часть else.

if (newval in ref) {
        outval = val;    ## this section never runs
} else {
        outval = newval  ## this sections runs for every tests
}

поэтому всякий раз, когда в строке newval=ref[val]ключ существует, outvalбудет принимать значение этого ключа, иначе для него будет установлено пустое значение. и, напечатав в print outval, это выведет значение этих ключей, если они были найдены в массиве ref[], или пустую строку в противном случае.

простое исправление (без дополнительных улучшений ), заменит эту строку на эту:

newval = (val in ref)?ref[val]:val

Ваша команда all может быть записана следующим образом:

$ awk 'BEGIN{ FS="," }
    NR==FNR   { ref[$1]=$2; next }
   ($1 in ref){ $1=ref[$1] }1' reference infile
100007
101
120
130
100007

$ cat reference
100,100007
$ cat infile
100
101
120
130
100
0
28.07.2021, 11:30

Дано

reffile="mycodes"
while(getline<reffile>0) {ref[$1]=$2}

пустая строка в mycodesсоздает элемент ref, значением которого является пустая строка, а индексом опять же является пустая строка.

Затем, при обработке входного потока, в

newval=ref[val]

newvalприсваивается пустая строка каждый раз, когда $1(100, 101, 120,130)не является 100, единственным индексом в ref, элемент которого не пуст (индексами являются начальные 100и""(пустые ), плюс пустые элементы, впоследствии созданные каждым newval=ref[val], т.е. 101, 120,130). В этих случаях, поскольку пустая строка является одним из индексов ref

if (newval in ref) { outval=val}
else               {outval=newval}

if (newval in ref)выполняется успешно, и напечатанное значение является текущим значением из входного потока (val, из val=$1).

С другой стороны, если refне имеет элемента с пустой строкой в ​​качестве индекса (, как это происходит, когда вmycodes)нет пустой строки, тогда if (newval in ref)терпит неудачу каждый раз, когда newvalявляется пустой строки. А затемnewval(печатается пустая строка ).

В обоих случаях, когда $1равно 100, newvalприсваивается значение 10007; if (newval in ref)терпит неудачу, поэтому newvalпечатается.

Обратите внимание, что то же загадочное поведение может быть вызвано пустой строкой во входном потоке, даже если в файле mycodesне было пустой строки.

Предполагая, что в вашем вопросе один или несколько из 10007, 100007и «пятизначный код» являются опечаткой, и вы на самом деле всегда имеете в виду10007(пять цифр ), я бы переписал ваш AWK запрограммировать как:

awk -v FS=, '
  NR == FNR {
    ref[$1] = $2
    next
  }
  ($1 in ref) {
    $1 = ref[$1]
  }
  1
'./mycodes -

или

awk '
  BEGIN {
    FS=","
    while ( (getline < "mycodes") > 0 )
      ref[$1] = $2
  }
  ($1 in ref) {
    $1 = ref[$1]
  }
  1
' -

(Спасибо αғsнιη за указание, что newval=ref[val]фактически добавляет valв качестве индекса к refи что ($1 in ref), следовательно, является более безопасным способом поиска в массиве соответствующего индекса ).

0
28.07.2021, 11:30
val=$1
newval=ref[val]
if (newval in ref) { outval=val }
else               { outval=newval }

Итак, вы читаете valиз основного входного файла, и это такие значения, как 100или 123. С ref, содержащим пары вроде ref[100]=100007, вы, вероятно, захотите проверить, существует ли valкак ключ в ref(, то есть существует ли элемент ref[val]). И не в том случае, если ref[val]существует как ключ (или ref[ref[val]]как элемент ).

Так сделай это if (val in ref).

Затем, если он существует , вы, вероятно, захотите использовать найденное оттуда значение (то, которое у вас есть в newval), а если не , то значение старое значение(val). Так сделай это

val=$1
newval=ref[val]
if (val in ref) { outval=newval }
else            { outval=val }

За исключением того, что, как упоминает @αғsнιη, теперь у вас есть проблема, заключающаяся в том, что присваиваниеnewval=ref[val]создаетref[val]с пустой строкой в ​​качестве значения, если она еще не существует, поэтому нам нужно что-то с этим сделать.

Либо вообще удалить newvalи использовать ref[val]только после теста:

val=$1
# newval=ref[val]     # remove this line
if (val in ref) { outval=ref[val] }
else            { outval=val }

Или оставьте его там и проверьте его на пустой строке:

val=$1
newval=ref[val]
if (newval != "") { outval=newval }
else              { outval=val }

Разница между ними имеет смысл, если mycodesможет содержать пустые значения во втором поле.

0
28.07.2021, 11:30

Если вы собираетесь использовать getlineдля заполнения $0, то вот как это сделать (см.http://awk.freeshell.org/AllAboutGetline):

while ( (getline < reffile) > 0 ) {
    ref[$1] = $2
}

и остальная часть вашего скрипта должна состоять из одной строки:

{ print ( $1 in ref ? ref[$1] : $1 ) }

так что весь сценарий:

BEGIN {
    FS = ","
    reffile = "mycodes"
    while ( (getline < reffile) > 0 ) {
        ref[$1] = $2
    }
}
{ print ( $1 in ref ? ref[$1] : $1 ) }

Я предполагаю, что у вас есть веская причина для создания переменной для хранения имени файла "mycodes"и вы не хотите передавать ее в качестве аргумента.

В качестве альтернативы вы можете просто сделать:

BEGIN { FS = "," }
NR==FNR { ref[$1] = $2; next }
{ print ( $1 in ref ? ref[$1] : $1 ) }

и назовите его awk 'script' mycodes file. Это немного менее эффективно, чем заполнение refs[]в BEGINциклом getline, но это вряд ли будет проблемой для большинства приложений и, очевидно, использует более краткий и -более сложный -для -получения -неверный код.

Выполнение print ( $1 in ref ? ref[$1] : $1 )немного более эффективно, чем выполнение if ($1 in ref) $1=ref; print $1или подобное, потому что оно не заставляет awk перестраивать текущую запись, но, опять же, маловероятно, что оно будет значительным.

Тем не менее, несмотря на то, что у него есть проблемы, ваш существующий скрипт, вероятно, не будет давать сбоев в том виде, как вы описываете, и ваша реальная проблема заключается в окончаниях строк DOS (см.https://stackoverflow.com/questions/45772525/why-does-my-tool-output-overwrite-itself-and-how-do-i-fix-it?).

2
28.07.2021, 11:30

Теги

Похожие вопросы