I есть следующий файл:
$less dummyKeyAndValue.txt
apiKey=key1;some_other_data;term=abc
apiKey=key2;some_other_data;some_other_data;term=def
term=pqr;some_other_data;apiKey=key1
apiKey=key3;some_other_data;term=def
Я хочу, чтобы результат был следующим:
$less dummyNewFile.txt
apiKey=key1 term=abc
apiKey=key2 term=def
apiKey=key1 term=pqr
apiKey=key3 term=def
В основном я хочу извлечь 'apiKey' и 'term' из файла dummyKeyAndValue.txt, они оба могут появляться в файле в разном порядке. Я попытался выполнить следующее. команда:
$cat dummyKeyAndValue.txt | tee >(egrep -o 'apiKey=[a-zA-Z0-9]+') |
egrep -o 'term=[a-zA-Z]+' | less
Я получаю вывод как:
term=abc
term=def
term=pqr
term=def
Может ли кто-нибудь помочь мне с командой для получения желаемого результата?
В качестве альтернативы очень эффективное, но немного более сложное решение
sed 'G;s/;/\n/' | awk -F= '
$1~/apiKey/ {key=$2}
$1~/term/ {term=$2}
/^$/ {printf(" apiKey=%s term=%s\n", key, term)
key=""
term=""}'
Сначала sed используется для двух вещей: команда «G» эффективно добавляет открытую строку после каждого «набора записей», а во-вторых, «заменяет» команда ( s /; / \ n /
) эффективно расширяет каждый набор записей до одной на строку, заменяя каждый ;
символом новой строки. Что выходит из sed, так это пары ключ-значение, по одной на строку, с открытой строкой, обозначающей конец каждой записи.
Затем awk нужно только просмотреть первое поле, чтобы найти интересующие вас атрибуты, и второе поле для значения, что устраняет необходимость в index и substr. Как только awk встречает «открытую строку», он печатает найденные значения. В целях устойчивости вы можете «очистить» значения в конце каждой записи. Обратите внимание на использование -F =
для указания awk разбить строку на поля на основе знака =
.
$ 1 ~ /.../
означает: «Когда первое поле соответствует значению /.../
, оно затем присваивает значение переменной (ключу или термину)
/ ^ $ /
означает «когда awk встречает открытую строку»
Это решение на основе awk может помочь, поскольку его легче читать и поддерживать. awk часто является предпочтительным инструментом для анализа значений, подобных столбцам, из текстового файла.
/tmp$ cat a.awk
{
keypart=substr($0, index($0, "apiKey=")+7)
keyvalue=substr(keypart, 1, index(keypart, ";")-1)
termpart=substr($0, index($0, "term=")+5)
termvalue=substr(termpart, 1, index(termpart, ";")-1)
# If the attribute is last on the input line there will be no ; to mark the end so use the whole part
if(keyvalue=="") {keyvalue=keypart}
if(termvalue=="") {termvalue=termpart}
printf (" apikey=%s term=%s\n", keyvalue, termvalue)
}
Сценарий Awk (названный выше a.awk, но можно использовать любое имя файла в смысле makse) можно использовать следующим образом:
awk -f a.awk inputfile
Как вы можете видеть, я обрабатываю случай поля ввода, которое заканчивается в конце строка специально с оператором if для каждого. Я бы улучшил этот скрипт следующим образом, чтобы автоматически обрабатывать эти случаи:
/tmp$ cat a.awk
{
LINE=$0 ";"
keypart=substr(LINE, index(LINE, "apiKey=")+7)
keyvalue=substr(keypart, 1, index(keypart, ";")-1)
termpart=substr(LINE, index(LINE, "term=")+5)
termvalue=substr(termpart, 1, index(termpart, ";")-1)
printf (" apikey=%s term=%s\n", keyvalue, termvalue)
}
Польза от этого становится яснее, когда вы добавляете больше случаев!
Вероятно не очень эффективно, но если вы хотите продолжить свой подход «двух greps», вы можете сделать это, используя paste
:
$ paste <(grep -o 'apiKey=[^;]*' dummyKeyAndValue.txt) <(grep -o 'term=[^;]*' dummyKeyAndValue.txt)
apiKey=key1 term=abc
apiKey=key2 term=def
apiKey=key1 term=pqr
apiKey=key3 term=def
Или подход KISS, используя GNU sed
:
sed -nE -e 's/(apiKey=[^;]*).*(term=[^;]*)/\1 \2/p' \
-e 's/(term=[^;]*).*(apiKey=[^;]*)/\2 \1/p' dummyKeyAndValue.txt