Tille - I can see you, read those man pages!   Tille's Site

Exercises on renaming files

Moving *.new to *.old

You will probably have seen that your shell gives you a message similar to the one below if you try to do it this way literally:

prompt> mv *.new *.old
mv: when moving multiple files, last argument must be a directory
Try `mv --help' for more information.

This is more like it:

prompt> ls
file1.new  file2.new  file3.new  file4.new

prompt> for i in $(ls *.new); do NAME=$i; NEWNAME=$(ls $i| cut -d "." -f 1).old; mv $NAME $NEWNAME; done

prompt> ls
file1.old  file2.old  file3.old  file4.old

We could have put this in a script, of course, in which we would start a new line after every semicolon. If you plan to use this kind of syntax regularly, that might be a wise idea.

Some explanation on the above syntax:

  • for i in $(ls *.new)

    Build a list of files that should be renamed.

  • do NAME=$i

    Assign the variable NAME to hold the filename.

  • NEWNAME=$(ls $i| cut -d "." -f 1).old

    Assign the variable NEWNAME to hold the new name of the file, which is the first part (before the dot) of the original name, followed by the string '.old'. Mind the dot, we cut it off, so we have to add it again.

  • mv $NAME $NEWNAME

    For each item in the list, move it to its new name.

  • done

    That's it.

You could have obtained the same result in a somewhat more elegant way like this:

prompt> for i in $(ls *.new); do NEWNAME=$(ls $i | sed -e 's/new/old'); mv $i $NEWNAME; done

A simple log rotation script

Say we have a set of logfiles named log, log.0, log.1, log.2, etcetera, following a classic log scheme such as you may find in any /var/log directory. The goal is to increase the indexnumbers by one, to make a new logfile without indexnumber and to keep the total amount of logfiles within limits. For testpurposes, we first create a script that includes the creation of a set of fake log files:

#!/bin/bash
# This is the preparation for a simple log rotation script.
# First, create a set of test files.

touch messages
touch messages.0
touch messages.1
touch messages.2

# Put the files to be renamed in reverse order in a list.  
# If you'd just use ls without the -r option, you'd only have one file left
# in the end.

LIST=$(ls -r messages*)

# Now see what we have.

for i in $LIST; do
        echo $i; 					# List the files

        TMP=$(ls $i | cut -d"." -f 2)			# See which indexnumber we have
        echo "(TMP = $TMP)"				# Print the indexnumber value

        if [ $TMP = "messages" ]; then			# If there is no index, this file 
                NEW=$TMP.0				# should be renamed to index 0
                echo mv $i $NEW	

        elif [ $TMP -gt 4 ]; then			# If the indexnumber is larger than 4,
                echo rm $i				# remove the file

        else
                BASE=$(ls $i | cut -d"." -f 1)
                NEW=$BASE.$(($TMP+1))			# If the indexnumber is smaller than
                echo mv $i $NEW				# or equals 4, just rename the file
        fi
done

We don't really do anything here, since we only used echo commands to see what the script is doing. In the real version, we use two arguments to the script: the first argument is the base log file name (without the indexnumber), the second argument is the maximum index number value. Here it is:

#!/bin/bash
# Simple log rotation script
LIST=$(ls -r $1*)
COUNT="$2"
for i in $LIST; do
        echo $i;
        TMP=$(ls $i | cut -d"." -f 2)
        if [ $TMP = $1 ]; then
                NEW=$TMP.0
                mv $i $NEW
        elif [ $TMP -gt $COUNT ]; then
                rm $i
        else
                BASE=$(ls $i | cut -d"." -f 1)
                NEW=$BASE.$(($TMP+1))
                mv $i $NEW
        fi
        touch $1
done

For testing, use the first script to populate a test directory, and the second for doing the renaming.

The problem is now that other files get renamed if we don't use any arguments to the log rotate script. So let's build in some safety procedures:

#!/bin/bash
# Logrotate script with dummy protection.
# If the amount of arguments to the script is not 2, then nothing is done.

if [ $# -ne 2 ]; then
        echo "Usage: logrot.sh base_name_to_rotate max_index_value"
        echo "e.g. logrot.sh messages 4"
        exit
fi

LIST=$(ls -r $1*)
COUNT="$2"
for i in $LIST; do
        echo $i;
        TMP=$(ls $i | cut -d"." -f 2)
        if [ $TMP = $1 ]; then
                NEW=$TMP.0
                mv $i $NEW
        elif [ $TMP -gt $COUNT ]; then
                rm $i
        else
                BASE=$(ls $i | cut -d"." -f 1)
                NEW=$BASE.$(($TMP+1))
                mv $i $NEW
        fi
        touch $1
done

Migrating from HTML to PHP

Even with very little knowledge, you don't need to be a hero to be able to sit back and watch. All my .html files needed to be converted to a file with the same base name but ending in .php, and then the PHP footer and header were to be added. Of course, the lines that made up the old HTML layout, such as <head>, <title> and <body> declarations, needed to be removed first.

Removing the HTML header is easy, that is always the same amount of lines at the beginning of the file. Removing the end, however, proves more difficult. The only thing we know is that the last 21 lines must be deleted. But at which line number do we start? I probably should read more man pages, but tac works just as well, preventing me from having to learn yet another combination of arguments and options and expressions.

Rather lazy than tired, here it is:

#!/bin/bash
# specific conversionscript for my html files to php
LIST=$(ls *.html)
for i in $LIST; do
        NEWNAME=$(ls $i | sed -e 's/html/php/')
        cat beginfile > $NEWNAME
        cat $i | sed -e '1,25d' | tac | sed -e '1,21d'| tac >> $NEWNAME
        cat endfile >> $NEWNAME
done

If all goes well, you may add a line to remove the html files. This scheme will of course only work if you wrote decent HTML files.

Home
© 1995-2010 Machtelt Garrels - tille - Powered by vIm - Best viewed with your eyes - Validated by W3C - Last update 20100511