bash tail the newest file in folder without variable

荒凉一梦 提交于 2021-01-19 08:28:12

问题


I have a bunch of log files in a folder. When I cd into the folder and look at the files it looks something like this.

$ 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

I want to look at the most recent messages in the most recent log file. I can now manually copy the name of the most recent log and then perform a tail on it and that will work.

$ tail -n 100 some_log_c48b72e8.log 

This does involve manual labor so instead I would like to use bash-fu to do this.

I currently found this way to do it;

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

It works, but I am bummed out that I need to save data into a variable to do it. Is it possible to do this in bash without saving intermediate results into a variable?


回答1:


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

You do not need ls to actually print timestamps, you just need to sort by them (ls -t). I added the -a option because it was in your original code, but note that this is not necessary unless your logfiles are "dot files", i.e. starting with a . (which they shouldn't).

Using ls this way saves you from parsing the output with sed and tail -c. (And you should not try to parse the output of ls.) Just pick the first file in the list (head -n 1), which is the newest. Putting it in quotation marks should save you from the more common "problems" like spaces in the filename. (If you have newlines or similar in your filenames, fix your filenames. :-D )

Instead of saving into a variable, you can use command substitution in-place.




回答2:


A truly ls-free solution:

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

There's no need to initialize newest, since any file will be newer than the null file named by the empty string.

It's a bit verbose, but it's guaranteed to work with any legal file name. Save it to a shell function for easier use:

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

Some examples:

# 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

A plug for zsh: glob qualifiers let you sort the results of a glob directly, making it much easier to get the newest file.

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

om sorts the results by modification time (newest first). [1,1] limits the range of files matched to the first. (I think Y1 should do the same, but it kept giving me an "unknown file attribute" error.)




回答3:


Without parsing ls, you'd use stat

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

Will break if your filenames contain newlines.


version 2: newlines are OK

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



回答4:


You can try this way also

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

Explanation :

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.


来源:https://stackoverflow.com/questions/32499365/bash-tail-the-newest-file-in-folder-without-variable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!