баш - я можу зробити: знайти… -виконати це && що?


23

Чи є спосіб логічно поєднати дві команди оболонки, на які викликається find - exec ?

Наприклад, щоб роздрукувати всі файли .csv, які містять рядок foo разом із його появою, я хотів би зробити:

find . -iname \*.csv -exec grep foo {} && echo {} \;

але bash скаржиться на "відсутні аргументи до" -exec ""


2
Ви можете використовувати 2 -execпослідовно або використовувати один -exec sh -c 'grep foo "$0" && printf %s\\n "$0"' {} \;.
jw013

Це спіткнувся мене неодноразово: Я завжди очікую , що перший аргумент , переданий sh(в даному випадку {}) буде $1і $0буде що - щось на зразок sh. Але насправді ви праві, перший аргумент показується як $0. Наявність першого аргументу - ім'я команди, що викликає, - це лише умова, яка не застосовується автоматично в цих випадках.
сумнівним

Можливо, слід злити
сумнівний

Відповіді:


24

-exec- це предикат, який виконує команду (не оболонку) і оцінює на істинну чи хибну на основі результату команди (нульовий або ненульовий статус виходу).

Так:

find . -iname '*.csv' -exec grep foo {} \; -print

буде надрукувати шлях до файлу, якщо він grepзнайде foo у файлі. Замість -printвас можна використовувати інший -execприсудок або будь-який інший присудок

find . -iname '*.csv' -exec grep foo {} \; -exec echo {} \;

Дивіться також оператори !та -oзнайдіть оператори для заперечення та або .

Крім того, ви можете запустити оболонку як:

find . -iname '*.csv' -exec sh -c '
   grep foo "$1" && echo "$1"' sh {} \;

Або щоб уникнути необхідності запускати оболонку для кожного файлу:

find . -iname '*.csv' -exec sh -c '
  for i do
    grep foo "$i" && echo "$i"
  done' sh {} +

10

Проблема, з якою ви стикаєтеся, полягає в тому, що оболонка спочатку аналізує командний рядок і бачить дві прості команди, розділені &&оператором:, find . -iname \*.csv -exec grep foo {}і echo {} \;. Цитування &&( find . -iname \*.csv -exec grep foo {} '&&' echo {} \;) обходить, але тепер команда виконується findщо - щось на зразок grepз аргументами foo, wibble.csv, &&, echoі wibble.csv. Вам потрібно доручити findзапустити оболонку, яка буде інтерпретувати &&оператора:

find . -iname \*.csv -exec sh -c 'grep foo "$0" && echo "$0"' {} \;

Зауважте, що перший аргумент після sh -c SOMECOMMANDє $0, ні $1.

Ви можете зберегти час запуску процесу оболонки для кожного файлу, згрупувавши виклики команд за допомогою -exec … +. Для зручності обробки передайте деяке фіктивне значення таким $0чином, щоб "$@"перерахувати назви файлів.

find . -iname \*.csv -exec sh -c 'for x in "$@"; do grep foo "$x" && echo "$x"; done' \ {} +

Якщо команда оболонки є лише двома програмами, розділеними &&, findможна виконати завдання самостійно: записати дві послідовні -execдії, а друга виконуватиметься лише в тому випадку, якщо перша закінчується зі статусом 0.

find . -iname \*.csv -exec grep foo {} \; -exec echo {} \;

(Я вважаю , що grepі echoпризначений тільки для ілюстрації, так як -exec echoможе бути замінений , -printі отриманий вихід не дуже корисно в будь-якому випадку.)


2
Я схильний уникати використання "$ 0" для цього, оскільки він також використовується оболонкою для відображення повідомлень про помилки. Наприклад, ви можете побачити заплутане ./some-file: grep: command not foundповідомлення про помилку. -exec find sh -c '... "$1"' sh {} \;не було б проблеми. У другій команді пошуку є помилка друку (пов'язана).
Стефан Шазелас

3

У цьому конкретному випадку я б зробив:

find . -iname \*.csv -exec grep -l foo \{\} \;

Або якщо у вас є анк :

ack -al -G '.*\.csv' foo

Щоб відповісти на власне запитання, щось подібне може спрацювати:

find . -iname \*.csv -exec sh -c "grep foo {} && echo {}" \;


3
Ця команда знаходження останнього не тільки не портативна, а й дуже небезпечна, оскільки шляхи файлів в кінцевому підсумку оцінюються як код оболонки.
Стефан Шазелас

Тим більше причин спробувати уникнути цього, використовуючи ack / grep належним чином :)
Dennis Kaarsemaker

1
Альтернатива jw013 (наведена в коментарі до питання) в цьому відношенні безпечніша. (Щойно зауважив, що у відповідях Гілла та Стефана використовується однакова техніка.)
сумнівним
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.