Bash функция поиска новейшего шаблона сопоставления файлов

В 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 script.

Ответ 1

Команда ls имеет параметр -t для сортировки по времени. Затем вы можете захватить первую (самую новую) с помощью head -1.

ls -t b2* | head -1

Но будьте осторожны: Почему вы не должны анализировать вывод ls

Мое личное мнение: разбор ls опасен только тогда, когда имена файлов могут содержать забавные символы, такие как пробелы или символы новой строки. Если вы можете гарантировать, что имена файлов не будут содержать забавные символы, тогда синтаксический анализ ls вполне безопасен.

Если вы разрабатываете script, который должен запускаться многими людьми во многих системах во многих разных ситуациях, я очень рекомендую не анализировать ls.

Вот как это сделать "правильно": Как я могу найти последний (самый новый, самый ранний, самый старый) файл в каталоге?

unset -v latest
for file in "$dir"/*; do
  [[ $file -nt $latest ]] && latest=$file
done

Ответ 2

Это возможная реализация требуемой функции 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 встроенные функции и должен обрабатывать файлы, имена которых содержат символы новой строки или другие необычные символы.

Ответ 3

Необычные имена файлов (такие как файл, содержащий допустимый символ \n, могут привести к хаосу такого разбора). Здесь можно сделать это в Perl:

perl -le '@sorted = map {$_->[0]} 
                    sort {$a->[1] <=> $b->[1]} 
                    map {[$_, -M $_]} 
                    @ARGV;
          print $sorted[0]
' b2*

Это Шварцское преобразование, используемое там.

Ответ 4

Существует гораздо более эффективный способ достижения этого. Рассмотрим следующую команду:

find . -cmin 1 -name "b2*"

Эта команда находит последний файл, созданный ровно минуту назад с поиском подстановочных знаков на "b2 *". Если вам нужны файлы за последние два дня, вам будет лучше использовать следующую команду:

find . -mtime 2 -name "b2*"

"." представляет текущий каталог. Надеюсь, это поможет.

Ответ 5

Комбинация find и ls хорошо работает для

  • имена файлов без символов новой строки
  • не очень большое количество файлов
  • не очень длинные имена файлов

Решение:

find . -name "my-pattern" ... -print |
    xargs -0 ls -1 -t |
    head -1

Позвольте сломать его:

С find мы можем сопоставить все интересные файлы следующим образом:

find . -name "my-pattern" ...

затем используя -print0, мы можем безопасно передать все имена файлов в ls следующим образом:

find . -name "my-pattern" ... -print0 | xargs -0 ls -1 -t

ls -t будет сортировать файлы по времени модификации (сначала самые новые) и распечатать их по одной строке. Вы можете использовать -c для сортировки по времени создания. Примечание: это сломается с именами файлов, содержащих символы новой строки.

Наконец head -1 доставит нам первый файл в отсортированном списке.

Примечание. xargs используйте системные ограничения для размера списка аргументов. Если этот размер превышает, xargs будет вызывать ls несколько раз. Это нарушит сортировку и, возможно, также окончательный вывод. Выполнить

xargs  --show-limits

чтобы проверить пределы вашей системы.