0

I would like to parse the n most recent files in a directory with a for loop. I thought about using ls -t piped to a head -n<number_of_files> but it is not working since I use files with whitespaces.

How should I modify the following script to parse only the n most recent files:

[ -n "$BASH_VERSION" ] && shopt -s nullglob

for f in *; do [ -e $f ] && echo $f || continue done

I am looking for a sh compatible solution.

1 Answers1

2

You've a check for $BASH_VERSION being (un)set which, to me, suggests you might be considering running this script under sh rather than bash. To that end we can omit nullglob because the code needs to check for this case anyway.

n=10    # Process no more than this number of files

k=0 for f in * do [ -f "$f" ] || continue k=$((k+1))

# Do stuff with your files as &quot;$f&quot;
:

[ $k -ge $n ] &amp;&amp; break

done echo "Files processed: $k"

You can make a couple of small changes if you're going to be using just bash

  • use [[ ... ]] instead of [ ... ]
  • replace k=$((k+1)) with ((k++))

Notice I've double-quoted my string variable everywhere I've used it. This protects its value from being parsed by the shell and split into words on whitespace. (In general, it's better to double-quote variables when you use them.)


I've re-read your question and realised you want the N most recently modified files. If you were using GNU tools I would use them to generate the list of files safely, but you have not specified these so I've resorted to piping from ls. In general this is not good practice, mainly because file names can contain non-printing characters and even newlines, but I don't know of a better non-GNU solution without dropping into zsh.

n=10    # Process no more than this number of files

k=0 ls -t | while IFS= read -r f do [ -f "$f" ] || continue k=$((k+1))

    # Do stuff with your files as &quot;$f&quot;
    :

    [ $k -ge $n ] &amp;&amp; break
done

With GNU tools I'd use this somewhat convoluted pipeline

find -maxdepth 1 -type f -printf "%T@\t%p\0" |    # Prefix numeric timestamp
    sort -z -k1,2rn |                             # Sort by the timestamp
    cut -z -f2- |                                 # Discard the timestamp
    head -z -n$n |                                # Keep only the top N files
    while IFS= read -r -d '' f
    do
        # Do stuff with your files as "$f"
        :
    done
Chris Davies
  • 116,213
  • 16
  • 160
  • 287