В Bash я хотел бы создать функцию, которая возвращает имя самого нового файла, соответствующего определенному шаблону. Например, у меня есть каталог таких файлов, как:
Directory/
a1.1_5_1
a1.2_1_4
b2.1_0
b2.2_3_4
b2.3_2_0
Мне нужен самый новый файл, который начинается с "b2". Как мне это сделать в bash? Мне нужно, чтобы это было в моем ~/.bash_profile
сценарии.
Ответы:
У
ls
команды есть параметр-t
для сортировки по времени. Затем вы можете получить первый (самый новый) с помощьюhead -1
.Но будьте осторожны: почему вы не должны анализировать вывод ls
Мое личное мнение: синтаксический анализ
ls
опасен только тогда, когда имена файлов могут содержать забавные символы, такие как пробелы или символы новой строки. Если вы можете гарантировать, что имена файлов не будут содержать забавных символов, синтаксический анализls
вполне безопасен.Если вы разрабатываете сценарий, который предназначен для запуска многими людьми во многих системах в самых разных ситуациях, я настоятельно рекомендую не выполнять синтаксический анализ
ls
.Вот как это сделать «правильно»: Как мне найти последний (самый новый, самый ранний, самый старый) файл в каталоге?
unset -v latest for file in "$dir"/*; do [[ $file -nt $latest ]] && latest=$file done
источник
ls
,printf "%s\n" b2* | head -1
сделаю это за вас.b2.10_5_2
убивает это решение.Комбинация
find
иls
подходит дляРешение:
find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t | head -1
Давайте разберемся:
С помощью
find
мы можем сопоставить все интересные файлы следующим образом:find . -name "my-pattern" ...
затем с помощью
-print0
мы можем безопасно передать все имена файловls
следующим образом:find . -name "my-pattern" -print0 | xargs -r -0 ls -1 -t
find
здесь можно добавить дополнительные параметры поиска и шаблоныfind . -name "my-pattern" ... -print0 | xargs -r -0 ls -1 -t
ls -t
отсортирует файлы по времени модификации (сначала самые новые) и распечатает их по одному. Вы можете использовать-c
для сортировки по времени создания. Примечание : это нарушит имена файлов, содержащие символы новой строки.Наконец,
head -1
мы получаем первый файл в отсортированном списке.Примечание:
xargs
используйте системные ограничения на размер списка аргументов. Если этот размер превышает,xargs
вызоветls
несколько раз. Это нарушит сортировку и, возможно, также окончательный результат. Бегатьчтобы проверить лимиты в вашей системе.
Примечание 2: используйте,
find . -maxdepth 1 -name "my-pattern" -print0
если вы не хотите искать файлы во вложенных папках.Примечание 3: как указано в @starfry -
-r
аргумент дляxargs
предотвращает вызовls -1 -t
, если файлы не были сопоставленыfind
. Спасибо за предложение.источник
find . -name "my-pattern" ... -print0
дает мнеfind: paths must precede expression: `...'
...
означает «больше параметров». Просто опустите его, если он вам не нужен.-r
в командную строку xargs, которая сообщает xargs не запускать свою командную строку, если она ничего не получает на свой стандартный ввод.-r
к ответу.Это возможная реализация требуемой функции Bash:
# Print the newest file, if any, matching the given pattern # Example usage: # newest_matching_file 'b2*' # WARNING: Files whose names begin with a dot will not be checked function newest_matching_file { # Use ${1-} instead of $1 in case 'nounset' is set local -r glob_pattern=${1-} if (( $# != 1 )) ; then echo 'usage: newest_matching_file GLOB_PATTERN' >&2 return 1 fi # To avoid printing garbage if no files match the pattern, set # 'nullglob' if necessary local -i need_to_unset_nullglob=0 if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then shopt -s nullglob need_to_unset_nullglob=1 fi newest_file= for file in $glob_pattern ; do [[ -z $newest_file || $file -nt $newest_file ]] \ && newest_file=$file done # To avoid unexpected behaviour elsewhere, unset nullglob if it was # set by this function (( need_to_unset_nullglob )) && shopt -u nullglob # Use printf instead of echo in case the file name begins with '-' [[ -n $newest_file ]] && printf '%s\n' "$newest_file" return 0 }
Он использует только встроенные функции Bash и должен обрабатывать файлы, имена которых содержат символы новой строки или другие необычные символы.
источник
nullglob_shopt=$(shopt -p nullglob)
а потом потом$nullglob
вернуть,nullglob
как было раньше.$()
или обратных кавычек), потому что это медленно, особенно в Cygwin, даже когда команда использует только встроенные команды. Кроме того, контекст подоболочки, в котором запускаются команды, может иногда вызывать их неожиданное поведение. Я также стараюсь избегать хранения команд в переменных (например,nullglob_shopt
), потому что могут произойти очень плохие вещи, если вы ошибетесь в значении переменной.cat
!». Даже если это требует больше работы, это помогает показать людям концепции. Получите +1!Необычные имена файлов (например, файл, содержащий допустимый
\n
символ, могут нанести ущерб подобному синтаксическому анализу. Вот способ сделать это в Perl:perl -le '@sorted = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, -M $_]} @ARGV; print $sorted[0] ' b2*
Здесь использовано преобразование Шварца .
источник
Используйте команду поиска.
Предполагая, что вы используете Bash 4.2+, используйте
-printf '%T+ %p\n'
для значения отметки времени файла.find $DIR -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
Пример:
find ~/Downloads -type f -printf '%T+ %p\n' | sort -r | head -n 1 | cut -d' ' -f2
Более полезный сценарий можно найти здесь: https://github.com/l3x/helpers.
источник
Вы можете использовать
stat
с файловым глобусом и decorate-sort-undecorate с указанием времени файла спереди:$ stat -f "%m%t%N" b2* | sort -rn | head -1 | cut -f2-
источник
stat
, если я правильно помню ее параметры. Чтобы получить аналогичный результат на других платформах, вы можете использоватьstat -c $'%Y\t%n' b2* | sort -rn | head -n1 | cut -f2-
Заклинание функции темной магии для тех, кто хочет
find ... xargs ... head ...
решение, описанное выше, но в простой в использовании функциональной форме, поэтому вам не нужно думать:#define the function find_newest_file_matching_pattern_under_directory(){ echo $(find $1 -name $2 -print0 | xargs -0 ls -1 -t | head -1) } #setup: #mkdir /tmp/files_to_move #cd /tmp/files_to_move #touch file1.txt #touch file2.txt #invoke the function: newest_file=$( find_newest_file_matching_pattern_under_directory /tmp/files_to_move/ bc* ) echo $newest_file
Печать:
Который:
Имя файла с самой старой измененной меткой времени файла в заданном каталоге, соответствующем заданному шаблону.
источник
Есть гораздо более эффективный способ добиться этого. Рассмотрим следующую команду:
find . -cmin 1 -name "b2*"
Эта команда находит последний файл, созданный ровно минуту назад, с поиском по шаблону «b2 *». Если вам нужны файлы за последние два дня, вам лучше использовать следующую команду:
find . -mtime 2 -name "b2*"
Знак "." представляет текущий каталог. Надеюсь это поможет.
источник