сократить командные каналы awk - PullRequest
1 голос
/ 22 марта 2019

довольно плохо знаком с использованием Linux на оболочке.

Я хочу уменьшить количество каналов, которые я использовал для извлечения следующих данных.

V       190917135635Z           1005    unknown /C=DE/ST=City/L=City/O=something/OU=Somewhat/CN=someserver.com/emailAddress=test@toast.com

Моя цель - поместить следующие значения в отдельный файл

190917135635 someserver.com

Команда, которую я сейчас использую, довольно длинная, с переадресацией и выглядит так

grep -v '^R' $file | awk '{print $2, $6}' | awk -F'[=|/]' '{print $1, $3}' | awk '{print $1, $3}' |  awk -F 'Z ' '{print $1, $2}' > sdata.txt

(файл содержит другие строки, начинающиеся с 'R', поэтому я исключаю их из моего grep)

Это законный способ сделать это?

Есть ли способ получить это в более короткой команде?

Большое спасибо!

Ответы [ 6 ]

1 голос
/ 22 марта 2019

Если это:

$ awk -F'[[:space:]/=]+' '!/^R/{print $2+0, $16}' file
190917135635 someserver.com

- это не все, что вам нужно, затем обновите свой вопрос, чтобы уточнить ваши требования и предоставить более по-настоящему репрезентативный пример ввода / вывода.

1 голос
/ 22 марта 2019

Еще один awk. Использование match для поиска записи CN и substr для ее извлечения для печати print, если она существует.

$ awk '!/^R/{
    print $2,
        (match($0,/CN=[^/]+/)?substr($0,RSTART+3,RLENGTH-3):"")  # 3==length("CN=")
}' file

Выход:

190917135635Z someserver.com
1 голос
/ 22 марта 2019

Похоже, что некоторые из ваших полей данных используются для создания сертификатов SSL, поэтому многие поля могут содержать ПРОСТРАНСТВА, т. Е. Город, название организации и т. Д. Вот почему вам нужно много строк awk (???). Вот один способ, который может помочь вам преодолеть эти проблемы. Таким образом, вместо преобразования существующей логики кода, цель состоит в том, чтобы найти имя домена, выполнив поиск по подстроке CN= и извлекая ее соответствующее значение.

awk  '
    !/^R/{
        start  = index($0, "CN=")+3
        end    = index(substr($0, start), "/")
        domain = end ? substr($0, start, end-1) : substr($0, start)
        print $2, domain
    }
' file.txt

Где:

  • мы используем index(), чтобы найти начальную позицию подстроки CN=, +3 будет отправной точкой доменного имени
  • затем мы ищем следующую /, чтобы получить конечную позицию этого домена. если он находится в конце строки, / не будет и, следовательно, end будет равно '0'
  • затем мы получаем доменное имя между подстрокой CN= и следующей '/', используя substr($0, start, end-1) или конец строки, используя substr($0, start).

Короткая версия:

awk '!/^R/{s=index($0, "CN=")+3; e=index(substr($0, s), "/"); print $2, substr($0, s, e ? e-1 : 253)}' file.txt

где 253 - самое длинное доменное имя, которого может быть достаточно для ваших нужд.

Обновление:

На самом деле, гораздо проще просто использовать match(), но смысл тот же:

awk '!/^R/{if(match($0, "/CN=([^/]*)")) print $2, substr($0, RSTART+4, RLENGTH-4)}' file.txt
0 голосов
/ 22 марта 2019

Вы используете $6 во второй команде awk, это означает, что ваш столбец 5th может содержать пробел s внутри, в отличие от показанных вами примеров данных, также он извлекаетсяCN= часть (CNAME?).

Итак, вот более совместимый и более точный способ sed, который не требует GNU sed:

sed -n -e '/^R/!{' -e 's|^[^[:space:]]*[[:space:]]*\([^[:space:]Z][^[:space:]Z]*\).*/CN=\([^/][^/]*\).*|\1 \2|p;}'

Если вам просто нужны цифры во втором столбце, и он начинается с цифры, тоВы можете изменить, чтобы использовать это:

sed -n -e '/^R/!{' -e 's|^[^[:space:]]*[[:space:]]*\([0-9][0-9]*\).*/CN=\([^/][^/]*\).*|\1 \2|p;}'
0 голосов
/ 22 марта 2019

Использование GNU sed:

sed -E -n '/^R/d; s/^[A-Za-z]\s+([0-9]+)\s+[0-9]+\s+.*\/CN=(.*)\/.*/\1 \2/p' input_file > new_file

0 голосов
/ 22 марта 2019

РЕДАКТИРОВАТЬ: Строго учитывая, что Input_file OP совпадает только с показанными примерами. После просмотра образцов OP можно попробовать следующее.

awk -F"[ =/Z]" '!/^R/{print $8,$37}'  Input_file


Для FUN :), если кто-то захочет попробовать подход OP, мы можем попробовать следующее.

awk '
!/^R/{
  val=$2 OFS $5
  split(val,array,"[ /Z]")
  val1=array[1] OFS array[9] OFS array[10]
  split(val1,array1,"[ =]")
  print array1[1],array1[3]
}
'  Input_file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...