Получить самый последний файл в каталоге в Linux

183

Ищите команду, которая вернет самый последний файл в каталоге.

Не вижу предельного параметра для ls...

извед
источник
1
watch -n1 'ls -Art | tail -n 1'- показывает самые последние файлы
Большинство ответов здесь анализируют вывод lsили используют findбез него, -print0что проблематично для обработки назойливых имен файлов. Всегда полезно упомянуть: BashFAQ099, который дает POSIX-ответ на эту проблему
kvantour

Ответы:

266
ls -Art | tail -n 1

Не очень элегантно, но это работает.

dmckee --- котенок экс-модератора
источник
2
используя ls -Artls, вы также можете просмотреть дату файла.
Иосир
13
Незначительная проблема: эта версия передает все выходные данные lsto tail, затем печатает только последнюю строку. ИМХО, лучше отсортировать в порядке возрастания и использовать headвместо этого, как chaosпредлагается. После печати первой строки заголовок завершается, поэтому отправка следующей строки (фактически следующего блока) вызовет SIGPIPE и lsтакже завершится.
Правда
1
@TrueY Я вполне согласен. Ответ Хаоса лучше для эффективности.
dmckee --- котенок экс-модератора
2
Обратите внимание, что это решение включает в себя каталоги, а также файлы. Это может быть хорошо или плохо; это зависит от того, что хочет отдельный пользователь. Причина, по которой я это поднимаю, заключается в том, что в первоначальном вопросе написано «файл».
Сильдорет
2
Я думаю, что предполагаемое преимущество использования tail вместо head может состоять в том, чтобы исключить включение строки, описывающей итоговое значение, возвращаемое ls.
Питер Скотт
155
ls -t | head -n1

Эта команда фактически дает последний измененный файл в текущем рабочем каталоге.

хаос
источник
Эквивалентно моему и, возможно, более эффективный.
dmckee --- котенок экс-модератора
не совсем работает для меня, так как я сначала выводю некоторую информацию в моем ls, но я получаю использование, спасибо!
извед
4
@Josir Это можно изменить, включив в него метку даты ls -tl | head -n 1, и не нужно проталкивать всю таблицу через канал, как это делает моя.
dmckee --- котенок экс-модератора
1
@ noɥʇʎԀʎzɐɹƆls -t *.png | head -n1
хаос
4
Возвращает папку, если она была изменена последним, используйте: ls -Art | head -n1если вам нужен последний измененный файл
achasinh
79

Это рекурсивная версия (т. Е. Она находит последний обновленный файл в определенном каталоге или любом из его подкаталога)

find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1

Изменить: использовать -f 2-вместо того, -f 2что предложено Кевином

Gioele
источник
5
Вот решение для Mac:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
пользователь
2
Проблема в том, что команда cut усекает пути с пробелами вместо -f 2, используя -f2-, чтобы вернуть поля 2 в конец строки
Кевин
2
Как и в предложении хаоса, если вы измените сортировку с помощью sort -nr, вы можете использовать head -n 1вместо tail -n 1и немного повысить эффективность. (Хотя, если вы сортируете рекурсивную находку, получение первой или последней строки не будет медленной частью.)
destenson
2
Очень полезно! Я нахожу это более дружелюбным, если по трубопроводу на ls:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Саймон
@ Версия Mac пользователя сортирует / отображает только дату, а не время. Вот исправленная версия:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
yoz
12

Примечание о надежности:

Поскольку символ перевода строки является таким же допустимым, как и любой в имени файла, любое решение, основанное на строках, подобных head/ tailbased, имеет недостатки.

В GNU lsдругой вариант заключается в использовании --quoting-style=shell-alwaysпараметра и bashмассива:

eval "files=($(ls -t --quoting-style=shell-always))"
((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

(добавьте -Aопцию, lsесли вы также хотите рассмотреть скрытые файлы).

Если вы хотите ограничить обычные файлы (не обращая внимания на каталоги, fifo, устройства, символические ссылки, сокеты ...), вам нужно прибегнуть к GNU find.

С bash 4.4 или новее (для readarray -d) и GNU coreutils 8.25 или новее (для cut -z):

readarray -t -d '' files < <(
  LC_ALL=C find . -maxdepth 1 -type f ! -name '.*' -printf '%T@/%f\0' |
  sort -rzn | cut -zd/ -f2)

((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

Или рекурсивно:

readarray -t -d '' files < <(
  LC_ALL=C find . -name . -o -name '.*' -prune -o -type f -printf '%T@%p\0' |
  sort -rzn | cut -zd/ -f2-)

Лучше всего было бы использовать zshи его глобальные квалификаторы вместо того, bashчтобы избежать всех этих хлопот:

Самый новый обычный файл в текущем каталоге:

printf '%s\n' *(.om[1])

В том числе скрытые:

printf '%s\n' *(D.om[1])

Второй новейший:

printf '%s\n' *(.om[2])

Проверьте возраст файла после разрешения символической ссылки:

printf '%s\n' *(-.om[1])

Рекурсивный:

printf '%s\n' **/*(.om[1])

Кроме того, с compinitвключенной системой завершения ( и со), Ctrl+Xmстановится завершителем, который расширяется до новейшего файла.

Так:

VI Ctrl+Xm

Заставит вас отредактировать новейший файл (вы также получите возможность увидеть, какой именно файл, прежде чем нажать Return).

VI Alt+2Ctrl+Xm

Для второго новейшего файла.

vi * .cCtrl+Xm

для новейшего cфайла.

vi * (.)Ctrl+Xm

для самого нового обычного файла (не каталога, не fifo / device ...) и т. д.

Стефан Шазелас
источник
Спасибо за zshсоветы. Не могли бы вы предоставить ссылку на более подробную информацию об этом в zsh docs?
заморожено
@freezed, смотритеinfo zsh qualifiers
Стефан Шазелас
Благодаря @Stephane Chazelas
замороженная
9

Я использую:

ls -ABrt1 --group-directories-first | tail -n1

Это дает мне только имя файла, исключая папки.

user1195354
источник
если только в каталоге нет только каталогов
ealfonso
8

ls -lAtr | tail -1

Другие решения не включают файлы, которые начинаются с '.'.

Эта команда также включает '.'и '..', что может или не может быть тем, что вы хотите:

ls -latr | tail -1

Джаред Оберхаус
источник
Вернется ли этот "." если каталог был изменен более недавно, чем какой-либо файл (скажем, удалением)? Может быть, это желаемое поведение, а может и нет. Но ты прав в любом случае.
dmckee --- котенок экс-модератора
6

Сокращенный вариант, основанный на ответе dmckee:

ls -t | head -1
Дмитрий Георгиевич Сергиенко
источник
но -1синтаксис для заголовка устарел довольно давно, и его -n 1следует использовать.
Тинк
5

Мне нравится echo *(om[1])( zshсинтаксис), поскольку он просто дает имя файла и не вызывает никакой другой команды.

MikeB
источник
1
Работает нормально, если вы используете Zsh. Вы не используете Zsh? Я думаю, что bash является значением по умолчанию в Ubuntu; Вы можете установить zsh или найти эквивалентную команду для bash.
MikeB
3
Команда "эхо"; он просто оценивает свои параметры и отправляет их на стандартный вывод. В этом случае квалификатор glob «om [1]» имеет «o», что означает упорядочение соответствующих файлов по «m», что является измененным временем. И из этого упорядоченного списка возьмите [1], который является первым файлом. Вы можете прочитать о квалификаторах глобуса
MikeB
4

Решение поиска / сортировки прекрасно работает до тех пор, пока количество файлов не станет действительно большим (как целая файловая система). Вместо этого используйте awk, чтобы отслеживать самый последний файл:

find $DIR -type f -printf "%T@ %p\n" | 
awk '
BEGIN { recent = 0; file = "" }
{
if ($1 > recent)
   {
   recent = $1;
   file = $0;
   }
}
END { print file; }' |
sed 's/^[0-9]*\.[0-9]* //'
Патрик
источник
3

Лично я предпочитаю использовать как можно меньше не встроенных bashкоманд (чтобы уменьшить количество дорогих системных вызовов fork и exec). Для сортировки по дате lsнужно позвонить. Но использование headне действительно необходимо. Я использую следующий однострочный (работает только на системах, поддерживающих именные каналы):

read newest < <(ls -t *.log)

или получить имя самого старого файла

read oldest < <(ls -rt *.log)

(Запомните пространство между двумя знаками «<»!)

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

Я надеюсь, что это может помочь.

TrueY
источник
Вы должны объяснить, что имя файла хранится в $ old / newest var. Но +1 для наименьшего количества вилок.
Квадрат
@squareatom Я думал, что чтение довольно хорошо известно, встроенный. Но вы правы, а может и нет. Спасибо за ваш комментарий!
TrueY
3
Предполагая, что вы знаете, что такое встроенное, вы, вероятно, правы. Но я просто подумал над вопросом ОП. Они попросили команду, которая вернет что-то. Технически ваше решение ничего не выводит. Так что просто добавьте "&& echo $ newest" или аналогичный до конца ;-)
squareatom
3

используя рекурсивную опцию R .. вы можете рассмотреть это как улучшение для хороших ответов здесь

ls -arRtlh | tail -50
mebada
источник
2
ls -t -1 | sed '1q'

Покажет последний измененный элемент в папке. Соединитесь с, grepчтобы найти последние записи с ключевыми словами

ls -t -1 | grep foo | sed '1q'
Ричард Сервелло
источник
что такое "1q"? 1для первой строки эквивалентно тому, head -n 1что q?
HattrickNZ
2

Рекурсивный:

find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head
Konki
источник
1

попробуйте эту простую команду

ls -ltq  <path>  | head -n 1

Если вам нужно имя файла - последнее изменение, путь = /ab/cd/*.log

Если вы хотите имя каталога - последнее изменение, путь = / ab / cd / * /

РИЧА АГГАРВАЛ
источник
1

Предполагая, что вам нет дела до скрытых файлов, которые начинаются с .

ls -rt | tail -n 1

В противном случае

ls -Art | tail -n 1
jasonleonhard
источник
1

Только со встроенными Bash, близко следуя BashFAQ / 003 :

shopt -s nullglob

for f in * .*; do
    [[ -d $f ]] && continue
    [[ $f -nt $latest ]] && latest=$f
done

printf '%s\n' "$latest"
Бенджамин В.
источник
0

Все эти Ls / хвост решение работает прекрасно для файлов в каталоге - игнорирование подкаталоги.

Чтобы включить все файлы в ваш поиск (рекурсивно), можно найти. gioele предложила отсортировать форматированный вывод find. Но будьте осторожны с пробелами (его предложение не работает с пробелами).

Это должно работать со всеми именами файлов:

find $DIR -type f -printf "%T@ %p\n" | sort -n | sed -r 's/^[0-9.]+\s+//' | tail -n 1 | xargs -I{} ls -l "{}"

Это сортирует по mtime, см. Человек найти:

%Ak    File's  last  access  time in the format specified by k, which is either `@' or a directive for the C `strftime' function.  The possible values for k are listed below; some of them might not be available on all systems, due to differences in `strftime' between systems.
       @      seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
%Ck    File's last status change time in the format specified by k, which is the same as for %A.
%Tk    File's last modification time in the format specified by k, which is the same as for %A.

Так просто заменить %Tс , %Cчтобы сортировать по CTime.

basic6
источник
Вы правы насчет проблемы пробелов с предложением @gioele, но вам нужно только добавить дефис к опции -f, чтобы задать диапазон, чтобы исправить это: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 Или, альтернативно, оставьте все, кроме первого поля: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Aaron
0

Нахождение самого последнего файла в каждом каталоге в соответствии с шаблоном, например, подкаталоги рабочего каталога, имена которых заканчиваются на «tmp» (без учета регистра):

find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;
XB.
источник
0
ls -Frt | grep "[^/]$" | tail -n 1
Жоао Фонсека
источник
1
Есть другие ответы, которые обеспечивают вопрос ОП, и они были опубликованы много лет назад. При публикации ответа, пожалуйста, убедитесь, что вы добавили либо новое решение, либо существенно лучшее объяснение, особенно когда отвечаете на старые вопросы.
help-info.de
2
@ help-info.de Пожалуйста, не голосуйте, чтобы удалить ответы, которые только для кода. Они могут не быть
хорошими
@Machavity - я надеюсь, что не потерпел неудачу и сделал комментарий только для позднего ответа.
help-info.de
0

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

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Если вы хотите сделать то же самое не для измененных файлов, а для файлов, к которым вы получили доступ, вам просто нужно изменить

% Y параметра из стат команды к % X . И ваша команда для самых последних доступных файлов выглядит так:

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Для обеих команд вы также можете изменить параметр var = "1", если хотите указать более одного файла.

OASE Software GmbH
источник
-1

Мне тоже нужно было это сделать, и я нашел эти команды. эти работы для меня:

Если вы хотите последний файл по дате его создания в папке (время доступа):

ls -Aru | tail -n 1  

И если вы хотите последний файл, который имеет изменения в его содержании (изменить время):

ls -Art | tail -n 1  
Масумех Вахид
источник