Як використовувати grep для всіх файлів нерекурсивно в каталозі?


34

Я хочу шукати рядок тексту у всіх файлах у каталозі (а не в його підкаталогах; я знаю, що -rваріант це робить, але це не те, що я хочу).

  1. Біг

    grep "string" /path/to/dir
    

    повинен був би це зробити, я читав, але це дає мені помилку:

    grep: dir: це каталог

  2. Далі я спробував запустити grepкілька файлів.

    grep "string" .bashrc .bash_aliases працює чудово.

    grep "string" .bash* працює також за задумом.

    grep "string" * дає мені помилки:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

Друкуються лише помилки, я не отримую відповідні рядки. Я спробував використати -sваріант, але безрезультатно.

Отже, мої запитання:

  1. Чому я не можу користуватися grepкаталогом, як у (1), коли мені це потрібно? Я бачив, що робиться в багатьох прикладах в Інтернеті.
    Редагувати : Коли я кажу "використовуючи grep для каталогу", я маю на увазі "пошук у всіх файлах у цьому каталозі, виключаючи його підкаталоги". Я вважаю, що саме це робить grep, коли передаєш йому каталог замість файлу. Я невірний?

  2. Будь ласка, дайте мені пояснення щодо роботи, grepяка б пояснила поведінку команд у (2).
    Редагувати : Дозвольте бути більш конкретним. Чому за допомогою символів підстановки можна вказати кілька файлів для пошуку роботи, .bash*а не з *або навіть ./*?

  3. Як я можу шукати всі файли в каталозі (а не його підкаталогах) за допомогою grep?


Також ви покладаєтесь на оболонки, що розширюють макіяж, такий як *, відомий як глобус. Globbing не включає в себе назви файлів, починаючи з крапки, такої .bashrcяк стандарт. Ви можете встановити параметри оболонки так, щоб вони включали ці файли, але ви можете трохи заблукати, якщо не знаєте, що робите. Хороший посібник із розуміння глобалізації можна знайти тут mywiki.wooledge.org/glob
Arronical

Я не знаю чому, але я завжди робив глобул на прихованих файлах, і це завжди працювало. Я не змінив жодної настройки чи чогось іншого. Як я зазначив у (2), він також працює grep "string" .bash*.
Джон Ред

Вибачте, мій останній приклад був невірним. Ви також можете шукати в прихованих файлах і придушувати "це каталог", оскільки Linux технічно розглядає каталоги як файл іншого типу. Команда була б тоді: grep "string" * .* 2>/dev/nullабоgrep -s "string" * .*
Терранс

Відповіді:


40

У Bash, Glob не розширюватиметься в приховані файли, так що якщо ви хочете знайти всі файли в каталозі, вам необхідно вказати приховані файли .*і не заховані *.

Щоб уникнути помилок "Є каталог", ви можете використовувати -d skip, але в моїй системі я також отримую помилку grep: .gvfs: Permission denied , тому я пропоную використовувати -s, яка приховує всі повідомлення про помилки.

Отже команда, яку ви шукаєте:

grep -s "string" * .*

Якщо ви шукаєте файли в іншому режимі:

grep -s "string" /path/to/dir/{*,.*}

Іншим варіантом є використання параметра dotglobоболонки, завдяки якому глобус включає приховані файли.

shopt -s dotglob
grep -s "string" *

Для файлів в іншому режимі:

grep -s "string" /path/to/dir/*

† Хтось сказав, що я не повинен отримувати цю помилку. Вони можуть мати рацію - я щось читав, але не міг сам це зробити ні головами, ні хвостами.


Чи є причина для проміжку між *і .*?
Хашим

2
@Hashim Порівняйте вихід echo * .*і echo *.*запустіть у своєму домашньому каталозі, і різниця повинна бути очевидною. Інакше LMK, і я поясню це.
wjandrea

Цікаво, тому echo *показує не приховані файли та папки, echo *.*показує не приховані файли, echo .*показує всі файли та echo * .*показує всі файли та каталоги. Але чому причина останнього між двома в останньому випадку? Мені здається безладним. Чи не існує способу поєднання двох, щоб отримати однакові результати? Або в іншому випадку є синтаксичне пояснення того, чому їх потрібно розділити тут, або це * .*виняток?
Хашим

1
@Hashim Я не впевнений, як ти дійшов до цих висновків, тому дозволь мені пояснити. По-перше, каталоги - це файли в цьому контексті. У глобусі *представляє всі не приховані файли (тобто імена файлів, які не починаються з крапки); .*представляє всі приховані файли (тобто імена файлів, які починаються з крапки); і *.*представляє всі не приховані файли, які містять крапку. В echo * .*, два глобуси повинні бути окремими, оскільки вони різні кулі: один для не прихованого, один для прихованого. Хоча як я писав у своїй відповіді, ви можете зробити *включені приховані файли, увімкнувши параметр dotglobоболонки.
wjandrea

1
Використання *.*є звичайним для Windows (DOS) як спосіб перерахувати всі файли, але в * nix буде міститись лише файли з крапкою, тому це не має сенсу для * nix. Натомість ви використовуєте *для переліку всіх файлів, крім прихованих, та .*списку прихованих файлів.
thomasrutter

10

Вам потрібна -d skipопція, додана.

  1. Grep здійснює пошук всередині файлів. Ви можете шукати рекурсивно, як ви вже говорили, якщо ви хочете шукати файли всередині каталогу.

  2. За замовчуванням grep прочитає всі файли, і він виявить каталоги. Оскільки за замовчуванням ви не визначилися, що робити з каталогами з -dопцією, це дає помилку виводу.

  3. Пошук просто в батьківському каталозі буде `grep -d пропустити" рядок "./*


Для отримання додаткової інформації про grep див man grep.
анонімний2

(a) Перегляньте редагування. (b) Використання -d skipне працює; це в основному те саме, що -s; також дивіться редагування. (c) Ні, теж grep -d skip "string" ./*не працює.
Джон Ред

7

Старі таймери, мабуть, зробили б це:

find . -type f -print0 | xargs -0 grep "string"

3
Чому ні find . -type f -exec grep string {} +?
wchargin

5
Ви також хочете -maxdepth 1.
wchargin

@wchargin: якщо ви хочете, щоб ім'я файлу у виході, коли є лише один файл, я думаю, що ви хочетеfind . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet

1
@GregoryNisbet: Просто перейдіть -Hдо grep.
wchargin

2

Перефразовування - ви хочете зібрати файли в одному рівні підкаталогу, але не повторюватись, хоча всі підкаталоги підподібних даних?

grep forthis  *  */*

Або якщо ви не хочете, щоб файли в поточному каталозі

grep forthis  */*

Зверніть увагу, що це не знайде каталогі, що починаються з крапки.

grep forthis  .*/*    */*   

повинен робити цю роботу.

Там також -maxdepthі -mindepthпараметри доступні обмеження на findкоманди теж.


Не вдалося б grep forthis */*шукати файли як у поточному каталозі, так і в одному каталозі?
Хашим

@Hashim nope здебільшого - cos відповідає */*лише речам з однією косою рисою. Якщо у вас був файл, названий a/bу поточному каталозі, то `* / * відповідатиме цьому.
Criggie

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.