Как напечатать все поля, содержащие одну из двух строк в таблице с awk

Я также использовал сценарий для создания таких пользователей:

useradd -u 12345 -g users -d / home / username -s / bin / bash -p '$ (openssl passwd -1 Whirlpool_Sauna_Soap)' username

1
20.09.2016, 03:36
3 ответа

Вы были близки, но вам нужно было извлечь первое значение, потому что вы не хотите печатать его для каждого совпадающего слова. Мы можем использовать printf , чтобы избежать новой строки.

awk '{printf "%s",$1
      for (i=1;i<=NF;i++)
      {
        if ($i ~ /dog|cow/) { printf " %s",$i; }
      }
      print ""
     }'

Результатом будет:

A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749

Его можно свернуть в одну строку:

awk '{printf "%s",$1; for (i=1;i<=NF;i++) { if ($i ~ /dog|cow/) { printf " %s",$i; }  } print ""  }'

Обратите внимание, что это напечатает строку, которая не соответствует ни одному слову , например,

E pig sheep

выведет

E
2
27.01.2020, 23:19

Если perl решение подходит:

$ cat ip.txt 
A   dog999   dog284   cow284   pig383   pig234   cow432   chicken432
B   cow394   cow432   cow345   dog983   pig345   chicken532 
C   dog847   pig357   pig236   cow395   dog496
D   dog392   cow237   cow749

$ perl -lane 'print join("\t",$F[0],grep {/cow|dog/} @F[1..$#F])' ip.txt 
A   dog999  dog284  cow284  cow432
B   cow394  cow432  cow345  dog983
C   dog847  cow395  dog496
D   dog392  cow237  cow749
  • -a разделите строку ввода на пробелы и сохраните ее в @F array
  • -l удалить символы новой строки из ввода и добавить обратно при печати
  • join добавит \ t между элементами при печати
  • $ F [0], grep {/ cow | dog /} @F [1 .. $ # F] первый элемент массива и все элементы, соответствующие cow или dog
  • Также можно использовать perl -lape '$ _ = join "\ t", shift (@F), grep / cow | dog /, @ F' . здесь shift удалит и вернет первый элемент массива @F , присвоение результата $ _ будет напечатано в конце любезно -p вариант (Совет Стефану Шазеласу )


Если строки, не содержащие cow или dog , должны быть проигнорированы:

perl -lane 'print join("\t",$F[0],grep {//} @F[1..$#F]) if /cow|dog/' ip.txt 
2
27.01.2020, 23:19

TXR awk macro:

$ txr -e '(awk (:let tmp)
               (:begin (set ofs "\t"))                     
               (f (set tmp (pop f))
                  (ff (keep-if #/cow|dog/))
                  (push tmp f) (prn)))' data
A   dog999  dog284  cow284  cow432
B   cow394  cow432  cow345  dog983
C   dog847  cow395  dog496
D   dog392  cow237  cow749

Разбивка:

  1. Пункт :let в макросе определяет локальные переменные. Этот макрос реализует "парадигму Awk", но в безопасном для типов языке, в котором переменные должны быть определены перед использованием. Поэтому в дополнение к таким пунктам, как :begin и :end (аналогично BEGIN и END в POSIX Awk), этот Awk предоставляет :let для определения переменных, лексически привязанных к макросу.

  2. (f (set tmp (pop f)) ...) - это условие-действие, где условием является f. If - это список разграниченных полей из записи; если он не пуст (не равен nil), то он ведет себя как булева истина. Поэтому формы действий выполняются, если в f есть что-либо.

  3. (set tmp (pop f)) берет первое поле из списка и сохраняет его во временной переменной tmp. Второе поле становится первым, третье - вторым и так далее. Когда мы работаем с f, запись rec также восстанавливается автоматически с помощью ofs, так же как в POSIX Awk запись $0 восстанавливается с помощью OFS между полями.

  4. (ff ...) фильтрует поля с помощью операции, в данном случае (keep-if #/regex/). По сути, мы удаляем из f все поля, которые не соответствуют регексу. ff - это оператор, видимый внутри макроса awk. keep-if - регулярная функция; здесь она неявно куррируется, поэтому аргумент list не появляется. Она ожидает функцию-предикат, но regex является вызываемой функцией, поэтому подходит в качестве предиката.

  5. Затем мы возвращаем сохраненное ранее первое поле в список полей f с помощью (push tmp f).

  6. (prn) является эквивалентом print. Без аргументов он печатает запись, за которой следует разделитель выходных записей (ors), который инициализируется новой строкой. Поскольку rec был восстановлен после всех манипуляций f, мы получаем отфильтрованный вывод.

Как можно видеть, парадигма Awk в основном сохранилась, просто в контексте другого языка, в котором возможны разные вещи. Удобство простого выполнения $2 > $1 без проверки того, что эти поля действительно существуют, отсутствует; но с другой стороны, нам не нужно писать циклы для обработки полей как структуры данных. Поля могут быть отображены через функции или рассматриваться как стек.

Perl-решение Сундипа примерно переводится в awk макросом следующим образом:

$ txr -e '(awk (t (prn `@[f 0]\t@{(keep-if #/cow|dog/ [f 1..:]) "\t"}`)))' data
0
27.01.2020, 23:19

Теги

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