Назад | Перейти на главную страницу

команда grep для поиска шаблона в нескольких файлах и упорядочивания файлов по дате

У меня есть требование найти шаблон в нескольких файлах и получить последний файл для дальнейшей обработки. Я пытаюсь сделать это в сценарии оболочки. Я пытался сделать это следующим образом

file=`grep -lh <pattern> <file_name> | tail -1`

Но grep перечисляет файлы как в ls а не как в ls -lrt. Я пробовал следующую команду

ls -lrt `grep -l <pattern> <file name>`

Но я не могу включить эту команду в сценарий оболочки. Любая помощь приветствуется.

Спасибо

Это много Быстрее. В то время как другие ответы grep все файлов, сначала выполняется поиск самых новых и останавливается, как только обнаруживается шаблон.

Этот однострочный файл фиксирует результат в переменной:

file=$(while read file; do grep pattern "$file" >/dev/null;[[ $? ]]; then echo "$file"; break; fi; done < <(find $startdir -maxdepth 1 -type f -printf "%T@:%p\n"|sort -nr|cut -d: -f2-))

Вот версия сценария Bash, которую легче читать:

#!/bin/bash
while read file
do
    grep pattern "$file" > /dev/null
    if [[ $? ]]
    then
        echo "$file"
        break
    fi
done < <(find $startdir -maxdepth 1 -type f -printf "%T@:%p\n" |
            sort -nr |
            cut -d: -f2-)

вы можете передать вывод grep в xargs, чтобы использовать ls -lrt перед передачей через хвост

Это должно сделать это:

ls -lrt|awk '{print $9}'|xargs -n1 grep <string>|tail -n1|awk '{print $1}'

Возможно, вам потребуется изменить, какие переменные в awk будут выводиться, в зависимости от вашей реализации ls и grep.

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

bluerain ~ # ls -lrt `grep -l a *.sh `
    -rwxr-xr-x 1 root root 315 2007-01-20 17:43 twopass.sh
    -rwxr-xr-x 1 root root  86 2007-04-21 16:23 hd_down.sh
    -rwxr-xr-x 1 root root 245 2009-09-10 19:47 pspenc.sh
    -rwxr--r-- 1 root root  95 2009-09-10 19:50 psp2.sh 
bluerain ~ # kk=`grep -l a *.sh` 
bluerain ~ # bb=` ls -rt $kk | tail -1` 
bluerain ~ # echo $bb psp2.sh 
bluerain ~ # echo $kk hd_down.sh psp2.sh pspenc.sh twopass.sh

поэтому используйте следующее:

tempvar=`grep -l <pattern> *(for all files in the directory)`
file=`ls -rt $tempvar | tail 1`

В вашем первом примере grep не следует повторно сортировать имена файлов, которые вы ему передаете. Если вы передаете их явно, он распечатает вывод в том же порядке, что и список файлов, которые вы ему передаете. Однако, если вы передаете подстановочный знак, вы правы, что ваша оболочка будет расширять этот подстановочный знак в лексическом порядке (что, по сути, ls по умолчанию, как вы отметили).

Рассмотрев другие предложения, я предлагаю следующее:

file=`ls -t --quoting-style=shell "dir" | xargs grep -l "regex" | head -n 1`

Я думаю, что это соответствует вашим требованиям и устраняет проблемы, поднятые другими, следующим образом:

  1. Ты можешь использовать ls -t без -l, поэтому нет необходимости анализировать вывод ls -l с участием awk или cut просто чтобы получить имя файла.
  2. Не меняйте порядок сортировки ls. С помощью ls -t помещает самые новые файлы на первое место и захватывает первый с помощью head закоротит конвейер, как только будет найден первый совпадающий файл (поэтому вы выполняете поиск в минимальном списке файлов, необходимых для поиска совпадения).
  3. Трубопровод к xargs эффективно позволяет выполнять поиск в неограниченном количестве файлов, не используя максимальную длину командной строки, и делает это без зацикливания.
  4. С помощью ls --quoting-style=shell при необходимости заключает имена файлов в одинарные кавычки, чтобы имена файлов со встроенными пробелами или управляющими символами обрабатывались правильно.

Обратите внимание, что --quoting-style является расширением GNU и вряд ли будет работать с не-GNU ls. У вас должно быть все в порядке с Linux. Следующее более переносимо, но добавляет вызов sed цитировать имена файлов, чтобы было немного больше накладных расходов:

file=`ls -t "dir" | sed 's/\(.*\)/"\1"/' | xargs grep -l "regex" | head -n 1`