2

I feel like I am missing something very simple and I was wondering if it possible to sow the last few lines of the last 4 modified files. I tried something like this

tail | ls -lt | head -5

but I think I should iterate over ls | -lt result and apply tail to it and I am not sure how to do it. Any help is appreciated

Morpheus
  • 163
  • 1
  • 2
  • 9
  • 1
    Does this answer your question? [Why \*not\* parse \`ls\` (and what to do instead)?](https://unix.stackexchange.com/questions/128985/why-not-parse-ls-and-what-to-do-instead) – Panki Nov 30 '20 at 08:18
  • And https://unix.stackexchange.com/a/108797 – muru Nov 30 '20 at 08:22
  • @Panki I think most of the discussion tells me that getting the file names to iterate over from `ls` is a bad idea. So I should probably think about a better approach – Morpheus Nov 30 '20 at 08:24
  • this seems a bit more relevant. https://askubuntu.com/questions/684220/how-to-list-the-last-modified-files-in-a-specific-directory-recursively – Morpheus Nov 30 '20 at 08:30

4 Answers4

5

Before I start, it’s generally considered bad practice to use the output of ls as input for something else; a common flaw being that it may not work as intended for files containing white space/new line in their name.

With that limitation in mind, you will probably find that ls | something will work OK most of the time.

You are heading in the right direction with your command, here is one solution with the above caveat about ls limitations:

ls -t | head -5 | xargs tail

This will throw a non fatal error if there are subdirectories in your listing.

bxm
  • 4,561
  • 1
  • 20
  • 21
4

In the zsh shell, the four most recently modified regular files in the current directory can be had by the globbing pattern

./*(.Dom[1,4])

... where ./* matches all names in the current directory and the parenthesis modifies the behavior of the matching. The . makes the * match only regular files while D makes it also match hidden names (as with the dotglob shell option enabled in the bash shell). The om orders the resulting list of names by modification timestamp and the [1,4] picks out the first four names.

To call tail on these files:

tail ./*(.Dom[1,4])

From the bash shell:

zsh -c 'tail ./*(.Dom[1,4])'

If you want consider all files in the current directory or anywhere below it, then use

zsh -c 'tail ./**/*(.Dom[1,4])'

The ** pattern works in a similar manner to the same globbing pattern in bash when the globstar shell option is enabled, i.e. it matches down into subdirectories recursively. The D in the glob qualifier would make the ** match into subdirectories with hidden names.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
1

May be this will help you

find . -type f -mmin -5 -ls | tail -4

In place of . => add your target directory path

This above command will get you the last modified 5 minutes ago files , if want you can increase your last modified minutes from 5 minutes to your need eg: 15min , 20min , 60min

codeholic24
  • 307
  • 3
  • 15
1

If there's no subdirectories, then this should work, even if the files have spaces in their names. It will however fail if the files have newlines in their names.

ls -1t | head -4 | tr '\n' '\0' | xargs -0 head -10

Unfortunately, it will fail if there is subdirectories. If there is, then this should work

find . -type f -maxdepth 1 -print0 | xargs -0 ls -1t | head -4 | tr '\n' '\0' | xargs -0 head -10

CSM
  • 2,090
  • 1
  • 10
  • 7