найти файл с помощью конкретного поиска в цикле while [closed]

col='REVISION' \
   perl -lne '
       $. == 1 and /(?:^|\s)(?=$ENV{col}(?:\s|$))/g and $h=pos, next;
       /^.{$h}/g; /\G(\S+)/ and print $1;
       next;
   ' yourfile


col='REVISION' \
   perl -lne '
      $. == 1 and $h = index($_, $ENV{col}), next;
      /^.{$h}/g; /\G(\S+)/ and print $1;
   ' yourfile

В первой строке мы вычисляем позицию REVISION , используя index () , работающий с текущей строкой $ _ . Для всех оставшихся строк мы пропускаем позиции посредством сопоставления /^.../g. Затем используйте привязку \ G , чтобы начать сопоставление с того места, где мы остановились ранее, и возьмите лежащие вне пробела символы \ S + .

1
20.07.2018, 18:24
3 ответа

Почему grep не работает

Выполнение этого в терминале:

Ошибка -Ожидание ввода
$ grep "index123"
Работает -Получает ввод от STDIN
$ echo -e "line1\nline2\nindex123blah\n" | grep "index123"
index123blah

Второй работает, потому что мы представили входные данные для grepдля синтаксического анализа через STDIN. grepпринимает ввод либо из стандартного ввода, либо из файла. В вашем сценарии:

if [[ "$d"=="*.out" && grep "index123"]]; then exit 1;  fi  

Он также не анализируется, следовательно, он не работает.

Ваша проблема

Судя по вашему коду, вы хотите что-то вроде этого. Для начала вот некоторые примеры данных:

$ mkdir -p 1/2/{3..5}
$ echo "index123" > 1/2/3/blah.out
$ echo "index123" > 1/2/3/blip.out
$ echo "index" > 1/2/blip.out
$ echo "index" > 1/2/blah.out

И измененная форма вашего скрипта:

$ cat loopy.bash
#!/bin/bash

while IFS= read -r d; do  
  grep -l "index123" "$d" && exit 1
done < <(find. -type f -name "*.out") 

Работа:

$./loopy.bash
./1/2/3/blah.out

Создает первый найденный файл со строкой index123и завершает работу.

Цикл while — хорошее решение?

Я бы так не поступил. Использование цикла whileздесь таким образом не обязательно. Было бы лучше использовать архитектуру find.... | xargs...или тип решения find... -exec.

См. ответ @DopeGhoti для лучшего подхода к использованию findс -execили xargs.

Печать каталога

Если вы просто хотите распечатать содержащее дерево каталогов, в котором находится соответствующий файл, вы можете использовать dirname, чтобы сделать это следующим образом:

$ cat loopy2.bash
#!/bin/bash

 while IFS= read -r d; do
   grep -q "index123" "$d" && dirname "$d"  && exit 1
 done < <(find. -type f -name "*.out")

И запустить его:

 $./loopy2.bash
./1/2/3
2
27.01.2020, 23:18

Вот ваша проблема:

if [[ "$d"=="*.out" && grep "index123"]];

Предположим, что d=foo.out. Теперь мы фактически имеем:

if [[ grep "index123"]];

Итак, вы пытаетесь указать grepискать в стандартном вводе выражение /index123/. Но на него не будет поступать никаких входных данных, так что он (будет казаться )зависшим, ожидая ввода. Однако он даже не зайдет так далеко, потому что if [[ grep "index123" ]]на первый взгляд является недопустимым синтаксисом. Вместо этого вы хотите if grep "index123". Но опять же --, это будет просто ждать стандартного ввода.

Похоже, вы хотите вернуть из findфайлы с именем *.out, которые содержат текст index123. Так что попробуй это:

find. -prune -type d -name \*.out -print0 | xargs -0 grep -l 'index123'

Однако это findутверждение довольно запутанно. Зачем findвсе, а затем обрезать каталоги, когда мы могли бы просто искать нужные нам файлы?

find. -type f -name \*.out -print0 | xargs -0 grep -l 'index123'

Теперь вы увидите все файлы, содержащие искомый текст.

Нам даже не нужно выносить xargsна стол, так как findможет вызвать grepсам по себе:

find. -type f -name \*.out -exec grep -l 'index123' "{}" \;
1
27.01.2020, 23:18

Поиск всех *.outфайлов, содержащих строку index123в текущем каталоге:

grep -lF 'index123'./*.out

Если вы хотите сделать рекурсивное grepдля всех *.outфайлов независимо от того, где они находятся в текущем каталоге:

find. -type f -name '*.out' -exec grep -lF 'index123' {} +

Печать каталога, в котором была найдена строка:

find. -type f -name '*.out' -exec grep -qF 'index123' {} ';' -exec dirname {} ';'

Выход после первого найденного имени каталога (с использованием GNUfind):

find. -type f -name '*.out' -exec grep -qF 'index123' {} ';' -exec dirname {} ';' -quit

В зависимости от того, для чего вы планируете использовать имя каталога, вы должны заменить -quitдругим -execдля обработки каталога любым способом, который вам нужен, или комбинировать различные -execутилиты в сценарий оболочки, вызываемый из -exec. Что вы не делаете, так это передаете имя каталога какой-либо другой команде, поскольку это, как правило, небезопасно, если вы не примете дополнительные меры предосторожности при разграничении имени пути (s )нулевыми символами.

Связанные:

1
27.01.2020, 23:18

Теги

Похожие вопросы