Changing Pieces of a String

Problem

You want to rename a number of files. The filenames are almost right, but they have the wrong suffix.

Solution

Use a bash parameter expansion feature that will remove text that matches a pattern.

#!/usr/bin/env bash
# cookbook filename: suffixer
#
# rename files that end in .bad to be .bash

for FN in *.bad
do
    mv "${FN}" "${FN%bad}bash"
done

Discussion

The for loop will iterate over a list of filenames in the current directory that all end in .bad. The variable $FN will take the value of each name one at a time. Inside the loop, the mv command will rename the file (move it from the old name to the new name). We need to put quotes around each filename in case the filename contains embedded spaces.

The crux of this operation is the reference to $FN that includes an automatic deletion of the trailing bad characters. The ${ } delimit the reference so that the bash adjacent to it is just appended right on the end of the string.

Here it is broken down into a few more steps:

NOBAD="${FN%bad}"
NEWNAME="${NOBAD}bash"
mv "${FN}" "${NEWNAME}"

This way you can see the individual steps of stripping off the unwanted suffix, creating the new name, and then renaming the files. Putting it all on one line isn’t so bad though, once you get used to the special operators.

Since we are not just removing a substring from the variable but are replacing the bad with bash, we could have used the substitution operator for variable references, the slash (/). Similar to editor commands (e.g., those found in vi and sed) that use the slash to delimit substitutions, we could have written:

# Not anchored, don't do this
mv "${FN}" "${FN/bad/bash}"

(Unlike the editor commands, you don’t use a final slash—the right-brace serves that function.)

However, one reason that we didn’t do it this way is because the substitution isn’t anchored, and will make the substitution anywhere in the variable. If, for example, we had a file named subaddon.bad then the substitution would leave us with subashdon.bad, which is not what we want. If we used a double slash for the first slash, it would substitute every occurrence within the variable. That would result in subashdon.bash, which isn’t what we want either.

# Anchored, so this is better, but TEST first
mv "${FN}" "${FN/.bad/.bash}"

There are several operators that do various sorts of manipulation on the string values of variables when referenced. Table 5-1 summarizes them.

Table 5-1. String-manipulation operators

inside ${ … }

Action taken

name:number:number

Substring starting character, length

#name

Return the length of the string

name#pattern

Remove (shortest) front-anchored pattern

name##pattern

Remove (longest) front-anchored pattern

name%pattern

Remove (shortest) rear-anchored pattern

name%%pattern

Remove (longest) rear-anchored pattern

name/pattern/string

Replace first occurrence

name//pattern/string

Replace all occurrences

Try them all. They are very handy.

See Also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.14.98