Size: 4317
Comment: tweak latest() directory filter
|
Size: 692
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
<<Anchor(faq3)>> == How can I find the latest (newest, earliest, oldest) file in a directory? == The tempting solution is to use `ls` to output sorted filenames and take the first result. As usual, the `ls` approach [[ParsingLs|cannot be made robust]] and should never be used in scripts due in part to the possibility of arbitrary characters (including newlines) present in filenames. Therefore, we need some other way to compare file metadata. The most common requirement is to get the most or least recently modified files in a directory. Bash and all ksh variants can compare ''modification times'' (mtime) using the `-nt` and `-ot` operators of the `conditional expression` compound command: {{{ # Bash/ksh unset -v latest for file in "$dir"/*; do [[ $file -nt $latest ]] && latest=$file done }}} Or to find the oldest: {{{ # Bash/ksh unset -v oldest for file in "$dir"/*; do [[ -z $oldest || $file -ot $oldest ]] && oldest=$file done }}} Keep in mind that ''mtime'' on directories is that of the most recently added, removed, or renamed file in that directory. Also note that `-nt` and `-ot` are not specified by [[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128|POSIX test]], however many shells such as [[Bashism|dash]] include them anyway. No bourne-like shell has analogous operators for comparing by ''atime'' or ''ctime'', so one would need external utilities for that; however, it's nearly impossible to either produce output which can be safely parsed, or ''handle'' said output in a shell without using nonstandard features on both ends. If the sorting criteria are different from "oldest or newest file by mtime", then GNU `find` and GNU `sort` may be used together to produce a sorted list of filenames + timestamps, delimited by NUL characters. This will of course operate recursively ([[UsingFind|GNU find's]] `-maxdepth` operator can prevent that); Here are a few possibilities, which can be modified as necessary to use ''atime'' or ''ctime'', or to sort in reverse order: {{{ # Bash + GNU find + GNU sort (To the precision possible on the given OS, but returns only one result) IFS= read -r -d '' latest \ < <(find "$dir" -type f -printf '%T@ %p\0' | sort -znr) latest=${latest#* } # remove timestamp + space }}} {{{ # GNU find + Bash w/ arrays (To the nearest 1s, using an undocumented "find -printf" format (%Ts).) while IFS= read -rd '' 'latest[$(read -rd "" y; echo $y)]' do : done < <(find "$dir" -type f -printf '%p\0%Ts\0') latest=${latest[-1]} }}} {{{ # GNU stat + Bash /w arrays (non-recursive w/o globstar, to the nearest 1s) while IFS= read -rd '' 'latest[$(read -rd "" y; echo $y)]' do : done < <(stat '--printf=%n\0%Y\0' "$dir"/*) latest=${latest[-1]} }}} One disadvantage to these approaches is that the entire list is sorted, whereas simply iterating through the list to find the minimum or maximum timestamp (assuming we want just one file) would be faster, however, depending on the size of the job the algorithmic disadvantage of sorting may be negligible in comparison to the overhead of using a shell. {{{ # Bash + GNU find unset -v latest time while IFS= read -r -d '' line; do t=${line%% *} t=${t%.*} # truncate fractional seconds ((t > time)) && { latest=${line#* } time=$t; } done < <(find "$dir" -type f -printf '%T@ %p\0') }}} Lastly, here's a more verbose variant for use in a library or .bashrc which can either return a result or assign directly to a variable: {{{ latest() { if [[ $FUNCNAME == ${FUNCNAME[1]} ]]; then unset -v x latest printf ${2:+'-v' "$2"} '%s' "$1" return fi if (($# > 2)); then echo $'Usage: latest <glob> <varname>\nError: Takes at most 2 arguments. Glob defaults to *' return 1 fi >&2 if ! shopt -q nullglob; then trap 'shopt -u nullglob; trap - RETURN' RETURN shopt -s nullglob fi local x latest for x in ${1-*}; do [[ -d $x || $x -nt $latest ]] && latest=$x done latest "$latest" ${2+"$2"} } }}} Readers who are asking this question in order to rotate their log files may wish to look into `logrotate(1)` instead, if their operating system provides it. ---- CategoryShell |
Theo Castano is how I'm called but may call me anything you like. Booking holidays is when I support my as well as I assume I'll put it back anytime now. My friends say it isn't good for me personally but things i love doing is magic and Let me never stop doing this situation. [[http://dictionary.Reference.com/browse/Arizona?s=ts|Arizona]] is where he and his wife live and he doesn't don't leave out changing so it. Go to his website to find out more: http://underneathmyfedora.tumblr.com/post/140243599436/a-crazy-story-randomness<<BR>><<BR>> <<BR>><<BR>> My page ... [[http://underneathmyfedora.tumblr.com/post/140243599436/a-crazy-story-randomness|how do i become a secret shopper]] |
Theo Castano is how I'm called but may call me anything you like. Booking holidays is when I support my as well as I assume I'll put it back anytime now. My friends say it isn't good for me personally but things i love doing is magic and Let me never stop doing this situation. Arizona is where he and his wife live and he doesn't don't leave out changing so it. Go to his website to find out more: http://underneathmyfedora.tumblr.com/post/140243599436/a-crazy-story-randomness<<BR>><<BR>>
My page ... how do i become a secret shopper