#awk
#awk
Вопрос:
Я пытаюсь использовать awk для того, чтобы делать определенные замены в текстовом файле на основе значений, взятых из другого файла. Более подробно и на простых примерах у меня есть необработанный файл A.txt это должно быть обработано:
000 y4fy 1 0h0l
000 rft5 1 yrt3
000 g34y 1 ht74
000 ll90 2 t964
000 ew3x 2 472e
000 jo7e 3 6rhf
000 f5gg 4 gs84
000 wp5y 5 6rru
000 3em1 6 c2cn
000 pti1 7 ldr3
000 4vhd 7 epp3
000 2kfb 8 twtv
и так далее…
Второй файл B.txt содержит подмножество значений поля $ 3 из A.txt:
2
5
7
Я пытаюсь сделать конкретные замены в поле $ 4 A.txt
на основе значений B.txt .
Теперь мы можем выделить два разных случая.
Case_1: допустим, текст susbstitution представляет собой одну строку TTTT
, и вывод должен быть:
000 y4fy 1 0h0l
000 rft5 1 yrt3
000 g34y 1 ht74
000 ll90 2 TTTT
000 ew3x 2 TTTT
000 jo7e 3 6rhf
000 f5gg 4 gs84
000 wp5y 5 TTTT
000 3em1 6 c2cn
000 pti1 7 TTTT
000 4vhd 7 TTTT
000 2kfb 8 twtv
в котором формат сохраняется.
Случай_2: текст susbstitution связан с определенным значением в B.txt , такие как:
2 HHHH
5 AAAA
7 MMMM
и результат должен быть:
000 y4fy 1 0h0l
000 rft5 1 yrt3
000 g34y 1 ht74
000 ll90 2 HHHH
000 ew3x 2 HHHH
000 jo7e 3 6rhf
000 f5gg 4 gs84
000 wp5y 5 AAAA
000 3em1 6 c2cn
000 pti1 7 MMMM
000 4vhd 7 MMMM
000 2kfb 8 twtv
В принципе, мне кажется, что case_1 является конкретным экземпляром case_2.
Поскольку такой процесс включает в себя сотни очень длинных файлов, я пытаюсь найти решение, которое использует awk вместо более медленного цикла чтения во время чтения в bash.
Через пару дней лучший код, который я получил для case_1:
while read val; do awk -v x="$val" '{if ($1 == "0000" amp;amp; $3 == x) $4 = "TTTT" ; else print $0}' A.txt; done < B.txt > res.txt
что, конечно, не работает.
Интересно, может ли кто-нибудь предложить решение для case_1 и,
надеюсь, для case_2. Спасибо.
Ответ №1:
Вы можете использовать:
Случай 1:
cat file1
2
5
7
cat file2
000 y4fy 1 0h0l
000 rft5 1 yrt3
000 g34y 1 ht74
000 ll90 2 t964
000 ew3x 2 472e
000 jo7e 3 6rhf
000 f5gg 4 gs84
000 wp5y 5 6rru
000 3em1 6 c2cn
000 pti1 7 ldr3
000 4vhd 7 epp3
000 2kfb 8 twtv
Затем используйте awk как:
awk 'NR == FNR {map[$1] = $2; next} $3 in map {s = (map[$3] == "" ? "TTTT" : map[$3]); sub(/[^[:blank:]] $/, s)} 1' file1 file2
000 y4fy 1 HHHH
000 rft5 1 HHHH
000 g34y 1 HHHH
000 ll90 2 TTTT
000 ew3x 2 TTTT
000 jo7e 3 AAAA
000 f5gg 4 gs84
000 wp5y 5 TTTT
000 3em1 6 c2cn
000 pti1 7 TTTT
000 4vhd 7 TTTT
000 2kfb 8 MMMM
Случай 2:
cat file1
2 HHHH
5 AAAA
7 MMMM
Затем запустите его как:
awk 'NR == FNR {map[$1] = $2; next} $3 in map {s = (map[$3] == "" ? "TTTT" : map[$3]); sub(/[^[:blank:]] $/, s)} 1' file1 file2
000 y4fy 1 0h0l
000 rft5 1 yrt3
000 g34y 1 ht74
000 ll90 2 HHHH
000 ew3x 2 HHHH
000 jo7e 3 6rhf
000 f5gg 4 gs84
000 wp5y 5 AAAA
000 3em1 6 c2cn
000 pti1 7 MMMM
000 4vhd 7 MMMM
000 2kfb 8 twtv
Чтобы сделать его более читаемым:
awk 'NR == FNR { # while processing first file
map[$1] = $2 # store $2 in an associative array with key as $1
next
}
$3 in map { # if $3 is found in associative array
# set $4=TTTT when value is empty otherwise use value stored in array
s = (map[$3] == "" ? "TTTT" : map[$3])
sub(/[^[:blank:]] $/, s)
} 1' file1 fil22
Комментарии:
1. выходной файл, который вы получаете, не соответствует ожиданиям, и я опубликовал его. Ваш входной файл (file1) отличается от моего (B.txt ). Вы как бы перепутали эти два дела.
2. Я объединил оба случая в один входной файл, чтобы одна и та же команда awk могла работать для обоих случаев. Разве это не работает?
3. просто сравните мои ожидаемые результаты для двух случаев с вашими, и вы поймете, что это не работает.
4. большое спасибо за ваш код, он работает нормально. Не могли бы вы, пожалуйста, объяснить код, в частности, как и почему вы использовали функцию map?
5.
map
это не функция. Это просто имя массива. Это тоже может быть что угодно подобноеarr
. Я добавил объяснение.