awk. Замена поля

Программирование на sh, быть может немного про альтернативные языки
Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
Termitnik
сержант
Сообщения: 169
Зарегистрирован: 2008-04-05 20:09:45
Откуда: Киев

awk. Замена поля

Непрочитанное сообщение Termitnik » 2008-09-12 14:25:30

Здравствуйте!
Необходимо в файле file в строке содержащей вхождение free заменить второе поле. Пишу:
awk "/free/ {sub(/$2/,\"some text\");print}" file
Но some text добавляется в начало строки, втрое поле остается. :(
Как правильно?

Хостинговая компания Host-Food.ru
Хостинг HostFood.ru
 

Услуги хостинговой компании Host-Food.ru

Хостинг HostFood.ru

Тарифы на хостинг в России, от 12 рублей: https://www.host-food.ru/tariffs/hosting/
Тарифы на виртуальные сервера (VPS/VDS/KVM) в РФ, от 189 руб.: https://www.host-food.ru/tariffs/virtualny-server-vps/
Выделенные сервера, Россия, Москва, от 2000 рублей (HP Proliant G5, Intel Xeon E5430 (2.66GHz, Quad-Core, 12Mb), 8Gb RAM, 2x300Gb SAS HDD, P400i, 512Mb, BBU):
https://www.host-food.ru/tariffs/vydelennyi-server-ds/
Недорогие домены в популярных зонах: https://www.host-food.ru/domains/

Гость
проходил мимо

Re: awk. Замена поля

Непрочитанное сообщение Гость » 2008-09-12 14:53:24

Termitnik писал(а):awk "/free/ {sub(/$2/,\"some text\");print}" file
заменить foo на bar в втором поле - sub("foo", "bar", $2)

zg
полковник
Сообщения: 5845
Зарегистрирован: 2007-12-07 13:51:33
Откуда: Верх-Нейвинск

Re: awk. Замена поля

Непрочитанное сообщение zg » 2008-09-12 15:10:16

образец дай, чего есть, чего надо, а там видно будет, чего и как заменять

Termitnik
сержант
Сообщения: 169
Зарегистрирован: 2008-04-05 20:09:45
Откуда: Киев

Re: awk. Замена поля

Непрочитанное сообщение Termitnik » 2008-09-12 15:19:11

Гость писал(а):
Termitnik писал(а):awk "/free/ {sub(/$2/,\"some text\");print}" file
заменить foo на bar в втором поле - sub("foo", "bar", $2)
Содержимое втрого поля может варьироваться, мне нужно заменить его целиком.
zg писал(а):образец дай, чего есть, чего надо, а там видно будет, чего и как заменять
Есть:
vlan31 ХХХ.ХХХ.ХХХ.ХХХ/ХХ free
Надо:
vlan31 YYY.YYY.YYY.YYY/YY free


zg
полковник
Сообщения: 5845
Зарегистрирован: 2007-12-07 13:51:33
Откуда: Верх-Нейвинск

Re: awk. Замена поля

Непрочитанное сообщение zg » 2008-09-12 15:28:08

Код: Выделить всё

zg# awk '{if ($1=="vlan31") $2="YYY.YYY.YYY.YYY/YY"; print}' 1.txt
vlan31 YYY.YYY.YYY.YYY/YY free
inet XXX.XXX.XXX.XXX netmask XXX.XXX.XXX.XXX
zg# cat 1.txt
vlan31 ХХХ.ХХХ.ХХХ.ХХХ/ХХ free
inet XXX.XXX.XXX.XXX netmask XXX.XXX.XXX.XXX
zg#
UPD: прочитал первый пост

Код: Выделить всё

zg# awk '{if (match($0, "free")) $2="YYY.YYY.YYY.YYY/YY"; print}' 1.txt
vlan31 YYY.YYY.YYY.YYY/YY free
inet XXX.XXX.XXX.XXX netmask XXX.XXX.XXX.XXX
zg#

Termitnik
сержант
Сообщения: 169
Зарегистрирован: 2008-04-05 20:09:45
Откуда: Киев

Re: awk. Замена поля

Непрочитанное сообщение Termitnik » 2008-09-12 15:58:22

Спасибо!

zrad
проходил мимо
Сообщения: 2
Зарегистрирован: 2009-04-13 16:24:37

Re: awk. Замена поля

Непрочитанное сообщение zrad » 2009-04-13 16:51:23

Всем привет.
Есть аналогичная задача, пытаюсь применить приведенный здесь скрипт, но не срабатывает.
Есть много файлов с именами в формате ГГММДДЧЧ.* примерно такого формата:

Код: Выделить всё

030209 1156 00011 9    9  717             8962XXXXABCD             702  05  35  702             702               4 0 2
030209 1156 00025 9                               333                      06  702             702               0 0 2
030209 1156 00019 7    9  714                 ZZZZZZZ             333  11                      333               4 0 1
030209 1156 00038 9    9  717             8926XXXXXXXX         ZZZZZZZ  26  15  714         ZZZZZZZ               4 0 2
Необходимо прямо внутри этих файлов, в строчках содержащих 8962XXXXABCD произвести замену значений в колонках №8 и №12 (считая с единицы).

Скрипт выглядит таким образом:

Код: Выделить всё

awk '{match($7, "8962XXXXABCD") $8="030"; print}' 0903*
awk '{match($7, "8962XXXXABCD") $12="030"; print}' 0903*
Но после запуска скрипта никаких изменений в файлах не наблюдается.
Так тоже пробовал, с таким же результатом:

Код: Выделить всё

awk '{if ($7=="8962XXXXABCD") $8="030"; print}' 0903*
awk '{if ($7=="8962XXXXABCD") $12="030"; print}' 0903*
Пробовал собрать все строки, которые содержат поисковое значение в один файл и для проверки провести замену в нем, но не помогло - в этом файле после запуска тоже все остается без изменений. Ошибок на стандартный вывод никаких не поступает.
Подскажите, как можно с этим справиться? Куда посмотреть?

zg
полковник
Сообщения: 5845
Зарегистрирован: 2007-12-07 13:51:33
Откуда: Верх-Нейвинск

Re: awk. Замена поля

Непрочитанное сообщение zg » 2009-04-13 17:12:56

zrad писал(а):Но после запуска скрипта никаких изменений в файлах не наблюдается.
-))) и не будет, пока вывод не завернёшь куда надо

zrad
проходил мимо
Сообщения: 2
Зарегистрирован: 2009-04-13 16:24:37

Re: awk. Замена поля

Непрочитанное сообщение zrad » 2009-04-13 18:06:16

Упс...
А есть способ сделать так, чтобы изменения происходили во входных файлах? Ну или чтобы на выходе сгенерировались копии этих файлов с идентичными именами и полным содержимым с отличием только в точках замен?

zg
полковник
Сообщения: 5845
Зарегистрирован: 2007-12-07 13:51:33
Откуда: Верх-Нейвинск

Re: awk. Замена поля

Непрочитанное сообщение zg » 2009-04-13 18:29:14

zrad писал(а):А есть способ сделать так, чтобы изменения происходили во входных файлах?
через временные файлы

Код: Выделить всё

cat some.file | обработка > tmp.file
mv tmp.file some.file

Demis
прапорщик
Сообщения: 496
Зарегистрирован: 2015-05-25 14:36:32

awk. Замена поля

Непрочитанное сообщение Demis » 2017-07-27 12:39:28

Просто добавлю пример другой обработки, чтобы не забыть самому.
Не факт, что это нельзя было сделать короче.
Уперся я в сортировку с датами в ком. строке шелла csh.
Есть, допустим, два файла, первый: cat file3

Код: Выделить всё

Apr  01 00:00:00 [чего-то там 1]
Apr  9 08:50:48 [чего-то там 8]
Apr  8 09:20:37 [чего-то там 3]
Apr  8 22:22:40 [чего-то там 4]
Apr  22 22:26:41 [чего-то там 225]
Apr  18 22:26:41 [чего-то там 25]
Apr  8 22:26:41 [чего-то там 5]
Apr  8 22:27:56 [чего-то там 6]
Apr  8 23:27:27 [чего-то там 7]
Apr  3 08:59:28 [чего-то там 2]
второй cat file4

Код: Выделить всё

08-Apr-2017 22:21:51 [чего-то там 10]
08-Apr-2017 22:27:57 [чего-то там 16]
08-Apr-2017 22:23:53 [чего-то там 12]
08-Apr-2017 22:24:54 [чего-то там 13]
18-Apr-2017 22:24:56 [чего-то там 2213]
18-Apr-2017 22:24:54 [чего-то там 213]
19-Apr-2017 22:24:54 [чего-то там 213]
08-Apr-2017 22:25:55 [чего-то там 14]
08-Apr-2017 22:26:56 [чего-то там 15]
08-Apr-2017 22:22:52 [чего-то там 11]
На выходе хочу получить все отсортированное по дате.
Вариант cat file3 file4|sort -g дает нам:

Код: Выделить всё

Apr  01 00:00:00 [чего-то там 1]
Apr  18 22:26:41 [чего-то там 25]
Apr  22 22:26:41 [чего-то там 225]
Apr  3 08:59:28 [чего-то там 2]
Apr  8 09:20:37 [чего-то там 3]
Apr  8 22:22:40 [чего-то там 4]
Apr  8 22:26:41 [чего-то там 5]
Apr  8 22:27:56 [чего-то там 6]
Apr  8 23:27:27 [чего-то там 7]
Apr  9 08:50:48 [чего-то там 8]
08-Apr-2017 22:21:51 [чего-то там 10]
08-Apr-2017 22:22:52 [чего-то там 11]
08-Apr-2017 22:23:53 [чего-то там 12]
08-Apr-2017 22:24:54 [чего-то там 13]
08-Apr-2017 22:25:55 [чего-то там 14]
08-Apr-2017 22:26:56 [чего-то там 15]
08-Apr-2017 22:27:57 [чего-то там 16]
18-Apr-2017 22:24:54 [чего-то там 213]
18-Apr-2017 22:24:56 [чего-то там 2213]
19-Apr-2017 22:24:54 [чего-то там 213]
т.е. совсем не то, что хочется. Хотя скажем cat file3 file4 | sort +1 -g дает:

Код: Выделить всё

Apr  01 00:00:00 [чего-то там 1]
Apr  3 08:59:28 [чего-то там 2]
Apr  8 09:20:37 [чего-то там 3]
Apr  8 22:22:40 [чего-то там 4]
Apr  8 22:26:41 [чего-то там 5]
Apr  8 22:27:56 [чего-то там 6]
Apr  8 23:27:27 [чего-то там 7]
Apr  9 08:50:48 [чего-то там 8]
Apr  18 22:26:41 [чего-то там 25]
08-Apr-2017 22:21:51 [чего-то там 10]
08-Apr-2017 22:22:52 [чего-то там 11]
08-Apr-2017 22:23:53 [чего-то там 12]
08-Apr-2017 22:24:54 [чего-то там 13]
08-Apr-2017 22:25:55 [чего-то там 14]
08-Apr-2017 22:26:56 [чего-то там 15]
08-Apr-2017 22:27:57 [чего-то там 16]
18-Apr-2017 22:24:54 [чего-то там 213]
18-Apr-2017 22:24:56 [чего-то там 2213]
19-Apr-2017 22:24:54 [чего-то там 213]
Apr  22 22:26:41 [чего-то там 225]
т.е. видно, что по второму полю сортировка работает, а по первому нет.
Решение нашел такое (в одну строку):

Код: Выделить всё

# ( ( cat file3 | awk '{ print $2 "-" $1 "-2017 " $3 " - " $0}' | sort ) && ( cat file4 | sort ) ) | awk '{first=substr($0,1,1);gsub("0","",first);end=substr($0,2);print first end}' | sort -g
На выходе получаем вроде то, что надо:

Код: Выделить всё

1-Apr-2017 00:00:00 - Apr  01 00:00:00 [чего-то там 1]
3-Apr-2017 08:59:28 - Apr  3 08:59:28 [чего-то там 2]
8-Apr-2017 09:20:37 - Apr  8 09:20:37 [чего-то там 3]
8-Apr-2017 22:21:51 [чего-то там 10]
8-Apr-2017 22:22:40 - Apr  8 22:22:40 [чего-то там 4]
8-Apr-2017 22:22:52 [чего-то там 11]
8-Apr-2017 22:23:53 [чего-то там 12]
8-Apr-2017 22:24:54 [чего-то там 13]
8-Apr-2017 22:25:55 [чего-то там 14]
8-Apr-2017 22:26:41 - Apr  8 22:26:41 [чего-то там 5]
8-Apr-2017 22:26:56 [чего-то там 15]
8-Apr-2017 22:27:56 - Apr  8 22:27:56 [чего-то там 6]
8-Apr-2017 22:27:57 [чего-то там 16]
8-Apr-2017 23:27:27 - Apr  8 23:27:27 [чего-то там 7]
9-Apr-2017 08:50:48 - Apr  9 08:50:48 [чего-то там 8]
18-Apr-2017 22:24:54 [чего-то там 213]
18-Apr-2017 22:24:56 [чего-то там 2213]
18-Apr-2017 22:26:41 - Apr  18 22:26:41 [чего-то там 25]
19-Apr-2017 22:24:54 [чего-то там 213]
22-Apr-2017 22:26:41 - Apr  22 22:26:41 [чего-то там 225]
Конечно не все красиво и нужно следить за годом, но уже полегче.

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 35454
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

awk. Замена поля

Непрочитанное сообщение Alex Keda » 2017-08-12 22:44:37

таки год в начало, месяц, потом дату
тока месяц должен быть числовой
и сортировать по человечески ...
Убей их всех! Бог потом рассортирует...

Demis
прапорщик
Сообщения: 496
Зарегистрирован: 2015-05-25 14:36:32

awk. Замена поля

Непрочитанное сообщение Demis » 2017-11-09 10:47:04

Alex Keda писал(а):таки год в начало, месяц, потом дату
тока месяц должен быть числовой
и сортировать по человечески ...
Месяц прописью из лога.
Понятно, что можно преобразование наворотить, но это как-то совсем наворочено будет...

И еще на заметку, в памятку...

Озадачился, тут намедни, фильтрацией данных в командной строке.

Суть вопроса в чем?

Есть некий текстовый файл с данными.
"Хочу посчитать количество встречающихся известных цифирь."

Звучит вроде просто.
Но, что я получаю...
Меня удручает:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 307"
odlkmax_23679_1509170974.418754, 307
odlkmax_17245_1509210784.571775, 307
odlkmax_17332_1509210793.818450, 307
odlkmax_29899_1509221316.862000, 307
odlkmax_3904_1509226874.866412, 307
odlkmax_31238_1508403581.170446, 655, 307
odlkmax_5509_1509256589.421416, 307
Ладно, допустим, а если так:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 30"
odlkmax_23679_1509170974.418754, 307
odlkmin_29851_1508380755.414015, 30
odlkmax_17245_1509210784.571775, 307
odlkmax_17332_1509210793.818450, 307
odlkmax_29899_1509221316.862000, 307
odlkmax_3904_1509226874.866412, 307
odlkmax_31238_1508403581.170446, 655, 307
odlkmax_5509_1509256589.421416, 307
то еще и "30-ка" добавляется.

Понятное дело, что если так:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 3"
то их вообще очень много получается.

Пробовал конструкцию вида:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 307" | awk '$2 == 307,$3 == 307'
odlkmax_23679_1509170974.418754, 307
odlkmax_17245_1509210784.571775, 307
odlkmax_17332_1509210793.818450, 307
odlkmax_29899_1509221316.862000, 307
odlkmax_3904_1509226874.866412, 307
odlkmax_31238_1508403581.170446, 655, 307
odlkmax_5509_1509256589.421416, 307
Взятую из http://khpi-iip.mipk.kharkiv.edu/librar ... g/p11.html

но в ней тоже есть "подводный камень".
Который заключается в том, что ", 655, 307" могут быть произвольными в своем порядке.

Т.е.

Код: Выделить всё

", 655, 307",
", 655, 307, 3030"
", 655, 455, 725, 836, 307"
А каждый из них это разное число i-тых элементов:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 307" | awk '$2 == 307,$3 == 307'
cat 2017-10-31_full.txt | grep ", 307" | awk '$2 == 307,$3 == 307,$4 == 307'
cat 2017-10-31_full.txt | grep ", 307" | awk '$2 == 307,$3 == 307,$4 == 307,$5 == 307'
Получается огород какой-то.
А хочется получить именно все содержащие "307-ые" или все "30-ые" строки.

Пробовал такой вариант:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 307" | awk 'match($0,/307/) {START2 = index($0,"307");print
307
307
307
307
307
307
307
но тоже с теми-же косяками.

Ближе всех такой вариант:

Код: Выделить всё

cat 2017-10-31_full.txt | awk '{for(i=1;i<=NF;i++){ if($i=="307"){print $i} } }'
307
307
307
307
307
307
307
Что правильно.

или так

Код: Выделить всё

cat 2017-10-31_full.txt | awk '{for(i=1;i<=NF;i++){ if($i=="30"){print $i} } }'
30
Что тоже правильно.

Но абсолютно не верно если условие достигает 3 (тройки).

Код: Выделить всё

cat 2017-10-31_full.txt | awk '{for(i=1;i<=NF;i++){ if($i=="3"){print $i} } }'
Т.к. есть тройки в строках с данными.
Что их отделить нужно фильтровать по ", 3",
но эти значения в i не подставишь, что логично.

Пробовал еще такие варианты:

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 307" | awk '{for(i=1;i<=NF;i++){ if($i=="307"){print $i} } }'
307
307
307
307
307
307
307
или

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 30" | awk '{for(i=1;i<=NF;i++){ if($i=="30"){print $i} } }'
30
или

Код: Выделить всё

cat 2017-10-31_full.txt | grep ", 3" | awk '{for(i=1;i<=NF;i++){ if($i=="3"){print $i} } }'
[на выходе пусто, что правильно]

Понятно, что само значение "3" это подставляется в виде переменной в скрипте.
Но, сначала, оное должно отработать в CLI.

Было подсказано, грамотным человеком, искать в направлении использования конструкции на sed (sed -n '/.*7.*/p')
Попробован пример для 7-ки.

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7" | sed -n '/.*7.*/p'
odlk3_7515_1498741105.011651, 7, 270
odlk3_31868_1498237437.342564, 35, 7
odlk3_19163_1498768687.158794, 717
в примере выше появляется строка 717, т.к. есть семерка.
Но для меня такая строка "лишняя".

Правильный результат должен был быть как:

Код: Выделить всё

odlk3_7515_1498741105.011651, 7, 270
odlk3_31868_1498237437.342564, 35, 7
Подбрал "вручную" некий вариант.
Но есть-ли в нем подводные камни?
Пока не понимаю.

Примерный алгоритм поиска решения:

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7"
odlk3_7515_1498741105.011651, 7, 270
odlk3_31868_1498237437.342564, 35, 7
odlk3_19163_1498768687.158794, 483, 717
Применим все-таки вариант "счетчик"

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7" | awk '{for(i=1;i<=NF;i++){if($i=="7") {print $1} } }'
odlk3_31868_1498237437.342564,
Смотрим по "второму принту"

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7" | awk '{for(i=1;i<=NF;i++){if($i=="7") {print $2} } }'
35,
Смотрим по "следующему принту"

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7" | awk '{for(i=1;i<=NF;i++){if($i=="7") {print $3} } }'
7
На выходе увидели одну "явную 7".

Попробуем поменять "принт" на i-тый элемент:

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7" | awk '{for(i=1;i<=NF;i++){if($i=="7") {print $i} } }'
7
Долго мусолил:
https://www.ibm.com/developerworks/library/l-awk1/
https://www.ibm.com/developerworks/libr ... k1-pdf.pdf

Пока догадался в чем "соль".
Пробуем добавить еще одно условие, теперь так:

Код: Выделить всё

cat 2017-06-30_full.txt | grep ", 7" | awk '{for(i=1;i<=NF;i++){if($i=="7" || $i=="7,") {print $i} } }'
7,
7
Эврика!
Первая "7," от первой строки, вторая "7" от второй строки и не имеет конечной запятой.
А третьей ("717", "71") и нет, т.к. не проходит под условие.

Модифицирую код в скрипте под пример:

Код: Выделить всё

count=`cat $file | grep ", $i" | awk -v Key="$i" '{for(k=1;k<=NF;k++){ if($k==Key || $k=="Key,"){print $k} } }' | wc -l|awk '{print $1}'`
И "вроде" теперь получаю правильные данные...
Хотя уверенности полной пока еще нет - про двойные цифири (это когда 30 и 307).
Правда вручную посчитанный массив с условием 30-307 дал такой-же результат как и скрипт.

Попробовал вручную еще пару массивов перепроверить, вроде тоже правильно получилось.
Но кто знает, всегда-ли это будет верный результат?

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 35454
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

awk. Замена поля

Непрочитанное сообщение Alex Keda » 2017-11-19 16:15:57

в базу чтоле сложите строки, с разбивкой по колонкам сразу...
а потом считайте что угодно и как угодно =)
Убей их всех! Бог потом рассортирует...