Identify and assign most recent file to shell variable
Solution 1
There's a number of characters in file names that would make that fail. You can improve it with:
#! /bin/sh -
cd /home/pi/JPGS || exit
fn=$(ls -t | head -n1)
mv -f -- "$fn" /home/pi/WWW/webpic.jpg
Leaving a variable unquoted in list context (in Bourne-like shells other than zsh
) is the split+glob operator, you almost never want to do that. --
marks the end of the options so "$fn"
will not be taken as an option if it starts with -
.
That still fails if filenames contain newline characters, but not space, tab, star, question mark, right square bracket, or start with dash.
Best is to use zsh
here:
#! /bin/zsh -
mv -f /home/pi/JPGS/*.jpg(.om[1]) /home/pi/WWW/webpic.jpg
(.om[1])
are glob qualifiers, they are a zsh
specific feature. .
restricts the glob to regular files (will not include symlinks, directories, devices...), om
is to order on modification time, and [1]
to only take the first file.
Note that if you want to assign that to a shell variable, that would have to be an array variable:
fn=(/home/pi/JPGS/*.jpg(.om[1]))
(not that it makes a lot of difference on how you use it later).
Solution 2
Listing file
You could reverse the logic on the ls
a bit.
$ ls -t | head -n1
Details
-t sort by modification time, newest first
Now it shows up first so we can use head
to return the first result.
NOTE: You could also sort the list by change time (ctime), though you're probably going to want to use modify time above - (mtime). The ctime is the last time the file status meta information was changed.
-c with -lt: sort by, and show, ctime (time of last modification of
file status information) with -l: show ctime and sort by name
otherwise: sort by ctime, newest first
For example:
$ ls -tc | head -n1
Moving the file
To do the move more cleanly you'll want to wrap the filename in double quotes.
Example
$ mv -f -- "$fn" /home/pi/WWW/webpic.jpg
This will work in the majority of cases, there are a handful of legal filenames where it won't, for example, files with new lines. But these, though legal, are rarely ever intentionally used.
Related videos on Youtube
Levon
#SOreadytohelp I am here to share what I know and to learn from those more experienced without the need to be rude or put down those who come to learn. I will never downvote a solution that is functional & answers OP's question (even if there are better solutions). I will upvote good solutions and questions. I may downvote incorrect solutions if they clearly don't solve OP's problem but always with a reason, how else can anyone benefit? Downvotes without explanation help no one (OP, SO or me). Pointing out errors/making suggestions allows for improving/correcting answers which benefits everyone on SO. I don't care for aggressive self-righteous know-it-all types. I wasn't born with all that I know now, and neither were you.
Updated on September 18, 2022Comments
-
Levon over 1 year
I have a directory of
.jpg
files that continuously grows. I want to copy the most recent one elsewhere. This is what I currently have and it works, just curious if there's a better way to identify the most recent jpg file rather than usingls
andtail
.#!/bin/bash cd /home/pi/JPGS fn=$(ls -rt1 | tail -1) mv -f $fn /home/pi/WWW/webpic.jpg
-
Levon over 10 yearsThanks - I have a few questions: What's the significance of the
--
and why is zsh preferable over bash here? I'm also not sure(.om[1])
does. -
Levon over 10 yearsThanks - I do know the filenames, so this won't be an issue. What is the advantage of using double-quotes around the variable?
-
Stéphane Chazelas over 10 yearshe'll probably want to sort on
mtime
(which reflects the modification time of the content of the file) rather thanctime
(which reflects the modification time of metadata as well). -
Stéphane Chazelas over 10 yearsNote that, portably (and as the documentation you quote mentions), you need the
-t
option as well:ls -tc
to sort on the inode-change time (andls -lc
to display the inode-change time, andls -ut
to sort on access time) -
Stéphane Chazelas over 10 years@Levon, answer updated with details.
-
slm over 10 years@Levon - double quotes protects the
mv
command in cases where there are spaces within the file names. -
Levon over 10 yearsThanks .. good to store this away for future possible use, my filenames are quite regular so I won't have to worry about special cases for this.
-
Levon over 10 yearsThanks, very useful info re the use of "" .. my current filenames won't have that problem, but I will start using this as the default way of doing things.
-
Levon over 10 yearsYou are right of course, my comment was with regard to the globing, not re
--
which is clearly important from a security standpoint too - thanks again -
hajikelist over 6 yearsinstead of "ls -t" you could perhaps use "find . -maxdepth 1 -type f | head -n1" to limit to regular files...
-
Stéphane Chazelas almost 4 years@hajikelist, that would not sort the list by modification time.