Переконайте перший найдовший рядок
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Команду надзвичайно важко читати без практики, оскільки вона змішує синтаксис оболонки та регулярного виразів.
Для пояснення спочатку скористаюся спрощеним псевдокодом. Рядки, що починаються з##
, не проходять в оболонці.
Цей спрощений код використовує ім'я файлу F і не залишає цитування та частин регулярних виразів для читабельності.
Як це працює
Команда має дві частини, а grep
- та wc
виклик:
## grep "^.{$( wc -L F )}$" F
wc
Використовується в розширенні процесу, $( ... )
так воно виконується до grep
. Він обчислює довжину найдовшої лінії. Синтаксис розширення оболонки змішується з синтаксисом регулярного виразу виразів заплутаним чином, тому я розкладу розширення процесу:
## wc -L F
42
## grep "^.{42}$" F
Тут розширення процесу було замінено на значення, яке воно поверне, створивши використовуваний grep
командний рядок. Тепер ми можемо легше читати регулярний вираз: він відповідає точно від початку ( ^
) до кінця ( $
) рядка. Вираз між ними відповідає будь-якому символу, окрім нового рядка, повтореному 42 рази. Комбіновані, тобто рядки, що складаються рівно з 42 символів.
Тепер повернемося до справжніх команд оболонок: grep
Опція -E
( --extended-regexp
) дозволяє не уникати значення {}
для читабельності. Опція -m 1
( --max-count=1
) змушує зупинитись після того, як буде знайдено перший рядок. Команда <
в wc
записує файл на його stdin, щоб запобігти wc
друку імені файлу разом із довжиною.
Які найдовші лінії?
Щоб зробити приклади більш зрозумілими з іменем файлу, що виникає двічі, я буду використовувати змінну f
для імені файлу; Кожен $f
у прикладі може бути замінений на ім'я файлу.
f="file.txt"
Показати перший найдовший рядок - перший рядок, який дорівнює найдовшому рядку:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Показати всі найдовші рядки - всі рядки, довгі як найдовші:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Показати останній найдовший рядок - останній рядок, який дорівнює найдовшому рядку:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Показати один найдовший рядок - найдовший рядок довший, ніж усі інші рядки, або не:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(Остання команда є навіть більш неефективною, ніж інші, оскільки вона повторює повну команду grep. Очевидно, її слід розкласти так, щоб вихід wc
і рядки, записані в, grep
були збережені до змінних.
Зауважте, що всі найдовші рядки насправді можуть бути усіма рядками . Для збереження змінної потрібно зберігати лише перші два рядки.)