Вопрос или проблема
RHEL 8, если это важно.
Мне нужно найти все строки в текстовом файле, которые соответствуют этим трем фильтрам:
cut -f1 -d: .pgpass | grep ^FISP | grep -E 'CDS|TAP' | grep PGS401
FISPCDSPGS401A
FISPCDSPGS401B
FISPTAPPGS401AA
FISPTAPPGS401AB
FISPTAPPGS401BA
FISPTAPPGS401BB
FISPTAPPGS401CA
FISPTAPPGS401CB
FISPTAPPGS401DA
FISPTAPPGS401DB
Это, аналогично расширенному глобированию bash, тот вид команды, который я ищу, но не совпадает.
cut -f1 -d: .pgpass | grep '^FISP@(CDS|TAP)PGS401'
cut -f1 -d: .pgpass | grep -E '^FISP@(CDS|TAP)PGS401'
В чем секрет?
EDIT1: все данные
$ cut -f1 -d: .pgpass | grep -v '^$'
FISPCDSPGS202a
FISPCDSPGS202a
FISPCDSPGS202c
FISPCDSPGS202b
FISPCDSPGS202b
FISPCDSPGS202c
FISPCDSPGS202
FISPCCPGS302a
FISPCCPGS302b
FISPCCPGS302a
FISPCCPGS302b
FISPCCPGS302c
FISPCCPGS302
FISPCDSPGS302a
FISPCDSPGS302b
FISPCDSPGS302a
FISPCDSPGS302b
FISPCDSPGS302c
FISPCDSPGS302
FISPTAPPGS302a
FISPTAPPGS302b
FISPTAPPGS302a
FISPTAPPGS302b
FISPTAPPGS302c
FISPTAPPGS302
FISPCCPGS405a
FISPCCPGS405b
FISPCCPGS405a
FISPCCPGS405b
FISPCCPGS405c
FISPCCPGS405
FISPCDSPGS405a
FISPCDSPGS405b
FISPCDSPGS405a
FISPCDSPGS405b
FISPCDSPGS405c
FISPCDSPGS405
FISPTAPPGS405a
FISPTAPPGS405b
FISPTAPPGS405a
FISPTAPPGS405b
FISPTAPPGS405c
FISPTAPPGS405
FISPCDSPGS202c
FISPCCPGS302c
FISPCDSPGS302c
FISPTAPPGS302c
FISPCCPGS405c
FISPCDSPGS405c
FISPTAPPGS405c
FISSLBXPGS202a
FISSLBXPGS202b
FISSLBXPGS302a
FISSLBXPGS302b
FISSLBXPGS405a
FISSLBXPGS405b
FISPCDSPGS401A
FISPCDSPGS401B
FISPTAPPGS401AA
FISPTAPPGS401AB
FISPTAPPGS401BA
FISPTAPPGS401BB
FISPTAPPGS401CA
FISPTAPPGS401CB
FISPTAPPGS401DA
FISPTAPPGS401DB
FISQCCPGS401A
FISQCCPGS401B
FISQCCPGS401A
FISQCCPGS401B
FISQCCPGS401C
FISQCCPGS401
FISQCDSPGS401A
FISQCDSPGS401B
FISQCDSPGS401A
FISQCDSPGS401B
FISQCDSPGS401C
FISQCDSPGS401
FISQTAPPGS401A
FISQTAPPGS401B
FISQTAPPGS401A
FISQTAPPGS401B
FISQTAPPGS401C
FISQTAPPGS401
EDIT1: “точка и звезда” похоже не работают.
$ cut -f1 -d: .pgpass | grep '^FISP.*(CDS|TAP).*PGS401'
$
EDIT 2: Как можно закрыть вопрос, сказав “нужны подробности или уточнения”, когда у него есть принятый ответ? Это не имеет смысла.
Команда, которую вы можете использовать:
cut -f1 -d: .pgpass | grep -E '^FISP.*(CDS|TAP).*PGS401'
Это будет искать (regex) ^FISP.*CDS.*PGS401
или ^FISP.*TAP.*PGS401
Вот результат выполнения на основе входных данных ВО:
# grep -E '^FISP.*(CDS|TAP).*PGS401' vv
FISPCDSPGS401A
FISPCDSPGS401B
FISPTAPPGS401AA
FISPTAPPGS401AB
FISPTAPPGS401BA
FISPTAPPGS401BB
FISPTAPPGS401CA
FISPTAPPGS401CB
FISPTAPPGS401DA
FISPTAPPGS401DB
Я бы попробовал использовать \
, чтобы переключить “специальное” состояние* ваших ()|
. Вы можете сделать это так:
grep '^FISP\(CDS\|TAP\)PGS401'
- “специальное” состояние: предшествование символу
\
переключает его из “просто часть строки” в “специальный для парсера регулярных выражений”, и наоборот. Сопоставление литерала^
это\^
.
Возможно, это то, что вы пытаетесь сделать:
awk -F':' '{$0=$1} /^FISP/ && /CDS|TAP/ && /PG5401/' .pgpass
или, может быть:
awk -F':' '{$0=$1} /^FISP.*(CDS|TAP).*PG5401/' .pgpass
без четких, проверяемых образцов входных данных и ожидаемого вывода это явно непроверенная догадка.
cut -f1 -d: .pgpass | grep -E '^FISP@(CDS|TAP)PGS401'
Кажется, вы добавили лишний @
в тот шаблон, который не соответствует ни одному из входных данных. Удаление этого исправляет вашу проблему:
printf '%s\n' \
FISPCDSPGS401A \
FISPCDSPGS401B \
FISPTAPPGS401AA \
FISPTAPPGS401AB \
FISPTAPPGS401BA \
FISPTAPPGS401BB \
FISPTAPPGS401CA \
FISPTAPPGS401CB \
FISPTAPPGS401DA \
FISPTAPPGS401DB |
grep -E '^FISP(CDS|TAP)PGS401'
FISPCDSPGS401A
FISPCDSPGS401B
FISPTAPPGS401AA
FISPTAPPGS401AB
FISPTAPPGS401BA
FISPTAPPGS401BB
FISPTAPPGS401CA
FISPTAPPGS401CB
FISPTAPPGS401DA
FISPTAPPGS401DB
.
Ответ или решение
Для эффективного поиска строк в текстовом файле с использованием утилиты grep
, особенно когда необходимо применить несколько фильтров в одной регулярной строке, ключевой момент заключается в правильной формулировке регулярного выражения и использовании соответствующих флагов.
Проблема
Вы хотите использовать комбинацию нескольких фильтров, чтобы получить строки, которые начинаются с FISP
, содержат либо CDS
, либо TAP
, и заканчиваются на PGS401
. В вашем решении с использованием команды cut
и нескольких последовательных grep
выражений может возникнуть сложности при объединении этих условий в одном регулярном выражении.
Решение
Рекомендуется использовать grep
с флагом -E
, который включает режим расширенных регулярных выражений. Это позволит вам использовать оператор |
для логического "ИЛИ" и круглые скобки для группировки. Таким образом, выражение будет выглядеть следующим образом:
cut -f1 -d: .pgpass | grep -E '^FISP.*(CDS|TAP).*PGS401'
Объяснение команды
cut -f1 -d:
: Эта часть команды разбивает файл.pgpass
по двоеточиям и выбирает первый столбец.grep -E
: Включает расширенные регулярные выражения, которые позволяют использовать сложные шаблоны, в том числе|
для выбора альтернатив.'^FISP.*(CDS|TAP).*PGS401'
:^FISP
: Строка должна начинаться сFISP
..*
: Произвольное количество любых символов.(CDS|TAP)
: ЛибоCDS
, либоTAP
..*
: Снова произвольное количество любых символов.PGS401
: Строка должна содержатьPGS401
.
Пример использования
Предположим, у нас есть файл .pgpass
, и команду выше мы можем протестировать с реальными данными:
$ cut -f1 -d: .pgpass | grep -E '^FISP.*(CDS|TAP).*PGS401'
На выходе мы получим ожидаемые строки:
FISPCDSPGS401A
FISPCDSPGS401B
FISPTAPPGS401AA
FISPTAPPGS401AB
FISPTAPPGS401BA
FISPTAPPGS401BB
FISPTAPPGS401CA
FISPTAPPGS401CB
FISPTAPPGS401DA
FISPTAPPGS401DB
Заключение
Использование регулярных выражений в grep
, особенно с флагом -E
, значительно упрощает задачу фильтрации данных. Благодаря правильному синтаксису вы можете комбинировать условия и эффективно находить необходимые строки в текстовых файлах. Надеюсь, данное объяснение поможет вам успешно решить вашу задачу.