Bash search function for the latest file mapping template

In Bash, I would like to create a function that returns the file name with the newest file that matches a specific pattern. For example, I have a file directory like:

Directory/ a1.1_5_1 a1.2_1_4 b2.1_0 b2.2_3_4 b2.3_2_0 

I want the new file to start with 'b2'. How to do this in bash? I need to have this in my ~/.bash_profile script.

+72
linux bash
May 04 '11 at 15:31
source share
5 answers

The ls has the -t option to sort by time. Then you can capture the first (newest) with head -1 .

 ls -t b2* | head -1 

But be careful: why you shouldn't parse ls output

My personal opinion: parsing ls is only dangerous when file names can contain funny characters, such as spaces or newlines. If you can guarantee that the file names will not contain funny characters, then ls parsing is completely safe.

If you are developing a script that should be run by many people on many systems in many different situations, I highly recommend not analyzing ls .

Here's how to do it β€œcorrectly”: How can I find the last (newest, oldest, oldest) file in a directory?

 unset -v latest for file in "$dir"/*; do [[ $file -nt $latest ]] && latest=$file done 
+135
May 04 '11 at 15:35
source share

This is a possible implementation of the required Bash function:

 # Print the newest file, if any, matching the given pattern # Example usage: # newest_matching_file 'b2*' # WARNING: Files whose names begin with a dot will not be checked function newest_matching_file { # Use ${1-} instead of $1 in case 'nounset' is set local -r glob_pattern=${1-} if (( $# != 1 )) ; then echo 'usage: newest_matching_file GLOB_PATTERN' >&2 return 1 fi # To avoid printing garbage if no files match the pattern, set # 'nullglob' if necessary local -i need_to_unset_nullglob=0 if [[ ":$BASHOPTS:" != *:nullglob:* ]] ; then shopt -s nullglob need_to_unset_nullglob=1 fi newest_file= for file in $glob_pattern ; do [[ -z $newest_file || $file -nt $newest_file ]] \ && newest_file=$file done # To avoid unexpected behaviour elsewhere, unset nullglob if it was # set by this function (( need_to_unset_nullglob )) && shopt -u nullglob # Use printf instead of echo in case the file name begins with '-' [[ -n $newest_file ]] && printf '%s\n' "$newest_file" return 0 } 

It uses only Bash built-in functions and must process files whose names contain newlines or other unusual characters.

+4
Nov 05 '14 at 20:46
source share

Unusual file names (such as a file containing a valid \n character may lead to chaos in this parsing). Here you can do it in Perl:

 perl -le '@sorted = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, -M $_]} @ARGV; print $sorted[0] ' b2* 

This is the Schwartz transformation used there.

+2
May 4 '11 at 16:11
source share

There is a much more efficient way to achieve this. Consider the following command:

 find . -cmin 1 -name "b2*" 

This command finds the last file created exactly a minute ago with the search for wildcards on "b2 *". If you need files in the last two days, you would be better off using the following command:

 find . -mtime 2 -name "b2*" 

"." represents the current directory. Hope this helps.

+2
Feb 15 '17 at 18:24
source share

The combination of find and ls works well for

  • file names without newlines
  • not very large number of files
  • not very long file names

Decision:

 find . -name "my-pattern" ... -print | xargs -0 ls -1 -t | head -1 

Let me break it:

With find we can map all interesting files as follows:

 find . -name "my-pattern" ... 

then using -print0 , we can safely pass all the file names to ls as follows:

 find . -name "my-pattern" ... -print0 | xargs -0 ls -1 -t 

ls -t will sort the files by modification time (first the newest) and print them one line at a time. You can use -c to sort by creation time. Note : this will break with file names containing newlines.

Finally, head -1 will deliver us the first file in the sorted list.

Note. xargs use system limits for the size of the argument list. If this size exceeds, xargs will call ls several times. This will disrupt the sorting and possibly also the final output. Run

 xargs --show-limits 

to check the limits of your system.

+2
Nov 23 '17 at 9:43 on
source share



All Articles