2015-09-10 6 views
1

У меня есть куча файлов журналов в папке. Когда я вхожу в папку и смотрю на файлы, она выглядит примерно так.bash tail самый новый файл в папке без переменной

$ ls -lhat 
-rw-r--r-- 1 root root 5.3K Sep 10 12:22 some_log_c48b72e8.log 
-rw-r--r-- 1 root root 5.1M Sep 10 02:51 some_log_cebb6a28.log 
-rw-r--r-- 1 root root 1.1K Aug 25 14:21 some_log_edc96130.log 
-rw-r--r-- 1 root root 406K Aug 25 14:18 some_log_595c9c50.log 
-rw-r--r-- 1 root root 65K Aug 24 16:00 some_log_36d179b3.log 
-rw-r--r-- 1 root root 87K Aug 24 13:48 some_log_b29eb255.log 
-rw-r--r-- 1 root root 13M Aug 22 11:55 some_log_eae54d84.log 
-rw-r--r-- 1 root root 1.8M Aug 12 12:21 some_log_1aef4137.log 

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

$ tail -n 100 some_log_c48b72e8.log 

Это связано с ручным трудом, поэтому вместо этого я хотел бы использовать bash-fu для этого.

В настоящее время я нашел этот способ сделать это;

filename="$(ls -lat | sed -n 2p | tail -c 30)"; tail -n 100 $filename 

Это работает, но я испугался, что мне нужно сохранить данные в переменную, чтобы сделать это. Можно ли сделать это в bash без сохранения промежуточных результатов в переменную?

+0

Лучшее решение заключается в том, чтобы ваш логгер использовал имена на основе временных меток для файлов журнала и использовал фиксированное имя типа 'current' для самого последнего файла. (Или символическая ссылка с фиксированным именем на самое последнее.) – chepner

ответ

6
tail -n 100 "$(ls -at | head -n 1)" 

Вам не нужно ls на самом деле печати метки времени, вам просто нужно сортировать их (ls -t). Я добавил параметр -a, потому что он был в вашем исходном коде, но обратите внимание, что это не обязательно, если ваши лог-файлы не являются «точечными файлами», то есть начинаются с . (чего им не следует).

Использование ls таким образом избавляет вас от разбора вывода с помощью sed и tail -c. (И you should not try to parse the output of ls.) Просто выберите первый файл в списке (head -n 1), который является самым новым. Помещение в кавычки должно избавить вас от более распространенных «проблем», таких как пробелы в имени файла. (Если у вас есть новые строки или аналогичные имена в ваших файлах, исправить свои имена файлов. :-D)

Вместо сохранения в переменную вы можете использовать замену команд на месте.

+2

В целом, полагаться на вывод 'ls' не очень рекомендуется, но в этом случае это, кажется, хороший способ. Вы также можете пойти на что-то вроде ['find. -type f -printf '% T @% p \ n' | sort -n | tail -1'] (http://stackoverflow.com/a/4561987/1983854) – fedorqui

+0

@fedorqui: Вы можете рассчитывать на выход 'ls' в любой день. Отвратительная вещь - * разбор * вывод 'ls -l'. Да, 'find' является более мощным инструментом в целом, и я могу только рекомендовать об этом узнать, но в этом случае простой' ls' дает решение acleaner. – DevSolar

+3

[Почему вы не должны анализировать вывод ls (1)] (http://mywiki.wooledge.org/ParsingLs) говорит, что _Unix разрешает почти любой символ в имени файла, включая пробелы, символы новой строки, запятые, символы канала и почти все, что вы когда-либо пытались использовать в качестве разделителя, кроме NUL_, а затем _ В режиме по умолчанию, если стандартный вывод не является терминалом, ls разделяет имена файлов на newlines_. Так что это 'ls' в целом, а не только' ls -l'. – fedorqui

1

Вы можете попробовать этот способ также

ls -1t | head -n 1 | xargs tail -c 50 

Объяснение:

ls -1rht  -- list the files based on modified time in reverse order. 
tail -n 1  -- get the last one file 
tail -c 50  -- show the last 50 character from the file. 
+2

'ls -1rht' ... Drop' -1' ('ls' только коллимирует вывод, если печать на терминал, вывод в трубу - это одна строка). Отбросьте '-r' и используйте' head' вместо 'tail'. Бросьте '-h', потому что, поскольку вы не * печатаете * timestamps (' -l'), вам не нужно указывать 'ls' печатать их для чтения человеком. ;-) – DevSolar

+0

У меня есть ваша точка ... – Kalanidhi

+1

@ Kalanidhi, так что отредактируйте свой ответ –

1

без разбора ls, вы бы использовать stat

tail -n 100 "$(stat -c "%Y %n" * | sort -nk1,1 | tail -1 | cut -d" " -f 2-)" 

сломается, если ваши имена файлов содержат переводы строк.


версия 2: новые строки в порядке

tail -n 100 "$(
    stat --printf "%Y:%n\0" * | 
    sort -z -t: -k1,1nr | 
    { IFS=: read -d '' time filename; echo "$filename"; } 
)" 
+1

Если он ломается с именами файлов, содержащих символы новой строки, это действительно не лучше, чем просто использование 'ls'. – chepner

2

Действительно ls -бесплатно решение:

tail -n 100 < <(
    for f in *; do 
    [[ $f -nt $newest ]] && newest=$f 
    done 
    cat "$newest" 
) 

Там нет необходимости инициализировать newest, так как любой файл будет новее, чем нуль файл с именем пустой строки.

Это немного подробный, но он гарантированно работает с любым юридическим именем файла.Сохраните его в функцию оболочки для более удобного использования:

tail_latest() { 
    dir=${1:-.} 
    size=${2:-100} 
    for f in "$dir"/*; do 
     [[ $f -nt $newest ]] && newest=$f 
    done 
    tail -f "$size" "$newest" 
} 

Некоторые примеры:

# Default of 100 lines from newest file in the current directory 
tail_latest 
# 200 lines from the newest file in another directory 
tail_latest /some/log/dir 200 

Разъем для zsh: GLOB классификаторы позволяют сортировать результаты Glob напрямую, что делает его гораздо проще получить новейший файл.

tail -n 100 *(om[1,1]) 

om сортирует результаты по времени модификации (сперва новые). [1,1] ограничивает диапазон файлов, сопоставляемых с первым. (Я думаю, что Y1 должен сделать то же самое, но он все время давал мне ошибку «неизвестного файла».)