У меня есть требование найти шаблон в нескольких файлах и получить последний файл для дальнейшей обработки. Я пытаюсь сделать это в сценарии оболочки. Я пытался сделать это следующим образом
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`
Я думаю, что это соответствует вашим требованиям и устраняет проблемы, поднятые другими, следующим образом:
ls -t
без -l
, поэтому нет необходимости анализировать вывод ls -l
с участием awk
или cut
просто чтобы получить имя файла.ls
. С помощью ls -t
помещает самые новые файлы на первое место и захватывает первый с помощью head
закоротит конвейер, как только будет найден первый совпадающий файл (поэтому вы выполняете поиск в минимальном списке файлов, необходимых для поиска совпадения).xargs
эффективно позволяет выполнять поиск в неограниченном количестве файлов, не используя максимальную длину командной строки, и делает это без зацикливания.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`