In the following script I'm trying to have an automated task to move all the screen shots I have taken with the "Prt Scr" button from ~/Pictures to ~/Pictures/ScreenShots
Any ideas why it's not working. I did it at first with the mv command but was told by my instructor do it with a for loop because of globbing issues.

#!/bin/bash

# This is a script to home keep my $HOME/Pictures directory from keeting clutered up
# with screenshots by moving them into their own directory.

ls ~/Pictures/Screenshots\ from*.png > /dev/null 2> /dev/null
EXITSTATUS=${?}

if [ ${EXITSTATUS} == 0 ]
then
    for ${i} in $( ls ~/Pictures/Screenshot\ from*.png )
        do
            mv ${i} /home/garrett/Pictures/ScreenShots/
        done
fi

#mv /home/garrett/Pictures/Screenshot\ from*.png /home/garrett/Pictures/ScreenShots/
#END#

Recommended Answers

All 13 Replies

I was just going to say, rather than writing an over-complicated script, would it be simpler to just use a one liner e.g.:
mv ~/Pictures/*.png ~/Pictures/ScreenShots

Or if the files all contain a particular structure to the name. e.g.
ScreenShot-dd-mm-yyyy.png
You could use:
mv ~/Pictures/ScreenShot*.png ~/Pictures/ScreenShots

But it sounds like your instructor has ruled both of those out. I'm not sure what he meant by globbing issues. If you are moving all .png files into the ScreenShots directory, then there isn't really a problem AFAICT. :/

So I guess off the top of my head, you want something like this?:

for files in `ls ~/Pictures/ScreenShot*.png`
do
    mv $files ~/Pictures/ScreenShots/
done

Or perhaps:

for files in `ls ~/Pictures/ | grep "ScreenShot" | grep ".png"`
do
    mv $files ~/Pictures/ScreenShots
done

If there is a particular, set-pattern to the filenames; rather than using two greps like above, you could construct a single regular expression in a call to grep to ensure the entire filename matches the pattern.

I'm not sure either of those examples with the for loop are essentially any different to the one liners I posted above though! :/

Here's what my code looks like now but I'm getting an erro to do with the fi command.

/home/garrett/bin/mvScreenShots.sh: line 14: syntax error near unexpected token `fi'
/home/garrett/bin/mvScreenShots.sh: line 14: fi

#!/bin/bash

# This is a script to keep my $HOME/Pictures directory from keeting clutered up
# with screenshots by moving them into their own directory.

ls ~/Pictures/Screenshot*png > /dev/null 2> /dev/null

if [ ${?} -eq 0 ]
then
    for i in ls ~/Pictures/
        do
            if [ ${i} == "Screenshot*png" ]
                mv ${i} /home/garrett/Pictures/ScreenShots/
            fi
        done
fi

#mv /home/garrett/Pictures/Screenshot\ from*.png /home/garrett/Pictures/ScreenShots/
#END#

Deleted!

You missed the "then" clause in this block: if [ ${i} == "Screenshot*png" ]

Here's what I'v got right now. It moves the Screenshot...png files just fine but when it moves a file it also prints this error to bash as soon as I open a terminal. Any ideas?

mv: cannot stat ls': No such file or directory

#!/bin/bash

# This is a script to keep my $HOME/Pictures directory from keeting clutered up
# with screenshots by moving them into their own directory.

ls ~/Pictures/Screenshot*png > /dev/null 2> /dev/null

if [ ${?} == 0 ] #{
then
    cd ~/Pictures
    for i in ls "Screenshot*png"
        do
                mv ${i} /home/garrett/Pictures/ScreenShots/
        done
fi #}
#END#

You need to put single backquotes around your ls command:

for i in `ls Screenshot*png`

The backquote character is the character used in the markdown language here on DW to enclose inline code. It is usually on the key at the far left of the top line of numbers (under the F keys). On a UK keyboard it's on the ¬ key. On a US keyboard, it's on the ~ key.

When I do that I get these errors.

mv: cannot stat `Screenshot': No such file or directory
mv: cannot stat `from': No such file or directory
mv: cannot stat `2013-07-02': No such file or directory
mv: cannot stat `11:05:31.png': No such file or directory

Oh yeah, sorry. I forgot to mention about losing the curly braces around the i variable in your mv command too! oops :/
mv $i /home/garrett/Pictures/ScreenShots/
That should clear that problem up!

Nope

mv: cannot stat `Screenshot': No such file or directory
mv: cannot stat `from': No such file or directory
mv: cannot stat `2013-07-02': No such file or directory
mv: cannot stat `21:14:58.png': No such file or directory

When I do it that way the mv command seems to be handed each world alone of each .png file and is trying to treat each word as a file untu it's self.

Really?? How odd! :/
Are you using a different shell like zsh or csh or something?

I'm using the default Bourne Again/bash shell on my Kubuntu 12.04 install, and I normally use Terminator rather than Konsole for my terminal emulator. But this script works for me without any errors on both:

#!/bin/bash

ls ~/Pictures/Screenshot*png > /dev/null 2> /dev/null

if [ $? -eq 0 ]
then
    for i in `ls ~/Pictures/Screenshot*png`
        do
                mv $i ~/Pictures/ScreenShots/
        done
fi

I use a few similar scripts to yours on my machine and the above syntax has never steered me wrong!

Hang on, {slaps forehead} I think you've probably got spaces in your filenames, that would cause the errors you're seeing! Not sure what to suggest offhand.... Brain has gone completely blank!

For filenames where there are spaces, the shell will incorrectly interpret the results from the ls command in the for i in statement. So each part of the filename that is separated by a space will be seen as a separate result.

From what you've posted, I'm guessing you have a file in your Pictures directory called Screenshot 2013-07-02 21:14:58.png. In which case in the results from the ls command the shell will see the ~/Pictures/Screenshot, the 2013-07-02 and the 21:14:58.png parts of the filename as three separate results.

I don't usually put spaces in my filenames, so I've never had to get around this problem.. Rubberman might have some ideas! I'll have a bit of a play when I can and will see what I can come up with!

OK, After a bit of searching online and reading various man pages (RTFM FTW!) I've come up with this:

#!/bin/bash

ls ~/Pictures/Screenshot*png > /dev/null 2> /dev/null

if [ $? -eq 0 ]
then 
    find ~/Pictures/ -name "Screenshot*png" -type f -print0 | ( 
        while read -r -d "" FILENAME 
        do 
            FILENAMES=("${FILENAMES[@]}" "$FILENAME")
        done

        for FILE in "${FILENAMES[@]}"
        do
            mv "$FILE" ~/Pictures/Screenshots/
        done 
    )
fi

Like your original script, it uses the result of the initial ls command to check whether there are any files to move. If there are files to move, we use the find command to get the names/paths of the files to be moved, using the -print0 option to null terminate each result rather than appending a newline to each.

As far as I understand it, doing this puts all of the results from find into one long line of text and each filename in the resultant string ends with a null.

Next we pipe the output of find to the rest of the script.

The next part of the script uses the read utility in a while loop to tokenise the string output by find into each separate filename (including any whitespace characters or other special/escaped characters). Using "" as a delimiter in the call to read makes the read utility read up to the first null it finds, so any special characters are kept intact in each file-name.

Each filename is read into a variable called FILENAME, which in turn is copied into an array called FILENAMES.

Finally we iterate through the array of filenames and move the files using the mv command.

A slightly more long-winded way around the problem, but it seems to do the trick!

Thanks guys. Got it working.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.