Как напечатать одну строку после соответствующего шаблона, используя команду awk sed или cut - PullRequest
0 голосов
/ 02 мая 2020

Я хочу напечатать содержимое текстового файла до совпадения одного символа с шаблоном. Я использовал команду awk, но не смог получить желаемый вывод.

Файл:

>cat abc1.txt
2020-05-02 07:48:44+0000

Что я пробовал:

>cat abc1.txt | awk '{print $1}'
2020-05-02

Желаемый вывод:

2020-05-02 07:48

Пожалуйста, помогите мне.

Ответы [ 6 ]

3 голосов
/ 02 мая 2020
$ echo '2020-05-02 07:48:44+0000' | awk -F: -v OFS=: '{print $1, $2}'
2020-05-02 07:48
$ echo '2020-05-02 07:48:44+0000' | cut -d: -f1-2
2020-05-02 07:48

Вы можете изменить разделитель поля по умолчанию на : символ и напечатать первые два поля

1 голос
/ 02 мая 2020

Если вы правильно представили природу вашей проблемы, вам не нужны awk, sed или cut. Вот четыре способа обработки текста с использованием только bash встроенных модулей:

1. bash Регулярные выражения

[[ $(<./abc1.txt) =~ (^.+): ]] && printf %s "${BASH_REMATCH[1]}"
  • $(<./abc1.txt): считывает содержимое файла abc1.txt и более эффективно, чем cat в соответствии с bash собственная man страница

  • =~: оператор регулярного выражения

  • (^.+):: захватить каждый символ от начала строки до персонажа сразу перед последним двоеточием

  • ${BASH_REMATCH[1]}: хранит список подстрок, соответствующих шаблону регулярного выражения; первая группа захвата (в скобках шаблона) хранится с индексом 1

2. bash Подстановка параметров

: "$(<./abc1.txt)"
printf %s "${_%:*}"
  • ${_%:*}: подчеркивание ссылается на аргумент предыдущей команды, то есть содержимое файла; и замена удаляет все от последнего двоеточия до конца строки

3. date

Поскольку очень ясно, что вы работаете с датой, которая указана в четко определенном формате (ISO-8601), команда date может делать то, для чего предназначена:

# -j flag available on macOS:
date -jf '%F %T%z' "$(<./abc1.txt)" +'%F %R'
# -d option on other systems:
# [credit: @WalterA (see comments below)]
date -d "$(<./abc1.txt)" +"%F %R"

При анализе даты используется строка формата ввода "%F %T%z", которая описывает, что представляет каждый компонент строки даты (см. Linux Руководство программиста - STRFTIME(3)) и переформатирует с использованием выходной строки "%F %R", которая в этом случае представляет строку даты, аналогичную исходной, но без часового пояса и без секунд .

4. printf

printf предназначен для форматирования текста. Так что здесь он просто форматирует текст для отображения первых 16 символов (фактически он ограничивает ширину столбца первого поля до 16 символов, но это не так):

printf '%16.16s\n' "$(<./abc1.txt)"

5. Подстрока

Аналогично (4), но с использованием подстановки параметров:

: "$(<./abc1.txt)"
printf "${_:0:16}"

Кроме (3) ¹ никто не выполняет вызовы внешних программ или команд, что обеспечивает большую мобильность, более высокая надежность / надежность, более эффективное выполнение (вообще говоря, но это не измеримо, если вы не обрабатываете сотни или более дат или файлов) и меньше системных ресурсов.

awk и sed это мощные большие пушки, а не особо легкие инструменты (оба они являются полноценными, полноценными по Тьюрингу языками сценариев сами по себе). Не тянитесь к ним только потому, что это делают все остальные, или потому, что это то, что вы знаете: узнайте, что bash может сделать как оболочка, и вы получите много пользы в дальнейшем.

¹ Некоторые системы включают версию printf, которая может форматировать даты с использованием любого из флагов, распознаваемых strftime, и будет хорошей альтернативой date, если она доступна. printf --help или man bash (в разделе о встроенных функциях) покажет, существует ли эта опция.

1 голос
/ 02 мая 2020

Используйте разделитель полей ввода и вывода (:) и удалите последний столбец с помощью GNU awk:

awk 'BEGIN{FS=OFS=":"} {NF--; print}' abc1.txt

или короче:

awk 'BEGIN{FS=OFS=":"} {NF--}1' abc1.txt

Вывод:

2020-05-02 07:48

См .: 8 Мощные встроенные переменные Awk - FS, OFS, RS, ORS, NR, NF, NF, FILENAME, FNR

1 голос
/ 02 мая 2020

1-е решение: Не могли бы вы попробовать следующее.

awk 'match($0,/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}/){print substr($0,RSTART,RLENGTH)}'  Input_file

2-е решение: С rev + awk, где это облегчает нашу замену.

rev Input_file | awk '{sub(/[^:]*:/,"")} 1' | rev

3-е решение: С возможностью временного буфера sed.

sed -E 's/([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}).*/\1/' Input_file

4-е решение: Если ваш Input_file всегда имеет одинаковый формат ввода, и вам не нужно проверять синтаксис даты, попробуйте.

awk 'match($0,/^.*:/){print substr($0,RSTART,RLENGTH-1)}' Input_file

5-е решение: Добавление только замещающей операции awk-решения.

awk '{sub(/:[0-9]{2}\+.*/,"")} 1'  Input_file

6-е решение: Установить значение разделителя полей и печатать только необходимые поля.

awk -F' |:' '{print $1,$2":"$3}' Input_file
0 голосов
/ 02 мая 2020

Я хочу напечатать содержимое текстового файла до один символ сопоставления с образцом.

Регулярное выражение, которое соответствует тому, что вы хотите сохранить:

[^:]*:[^:]*

Две эквивалентные команды sed для сохранения только того, что соответствует этому:

sed 's|\([^:]*:[^:]*\).*|\1|'
sed -E 's|([^:]*:[^:]*).*|\1|'

Пример вывода:

$ echo '2020 07:48:40:40+0000'|sed 's|\([^:]*:[^:]*\).*|\1|'
2020 07:48
0 голосов
/ 02 мая 2020

Yon может использовать функцию sub в awk, чтобы удалить все после последнего появления ::

awk '{sub(/:[^:]*$/, "")} 1' abc1.txt

2020-05-02 07:48
...