I have a very long list of folders with the following naming convention
ABS1789_2563-01
ABS1789_2563-02
ABS1789_2563-02
.
.
.
How can I add " - " between ABS and 1789 then replace "_" by "-" between 1789 and 2563 using bash?
IFS="\n" # Handle files with spaces in the names
for file in ABS*; do
newfile="${file/ABS/ABS-}" # Add the hyphen following ABS
newfile="${newfile/_/-}" # Change the underscore to a hyphen
mv "$file" "$newfile" # Make the change
done
In light of Tony's comments below, a more general use version could be as follows:
IFS="\n" # Handle files with spaces in the names
for file in ABS*; do
newfile="${file/foo/bar}" # Replace foo with bar
newfile="${newfile/baz/quux}" # Replace baz with quux (repeat as needed)
if [[ "$file" == "$newfile" ]]; then
echo "Not renaming $file - no change decreed."
elif [[ -f "$newfile" ]]; then
echo "Not renaming $file - $newfile already exists."
else
mv -- "$file" "$newfile" # Make the change
fi
done
IFS is unnecessary, even if your files have spaces (I have tested this in Bash). In the general case (where, unlike here, you can't guarantee a substitution), it may be worth testing [ "x$file" = "x$newfile" ] || mv -- "$file" "$newfile" to avoid mv complaining about old and new being equal if neither substitution matches (I've also protected against files beginning with -, which we know won't happen in this specific case).
A suitable answer depends on how the names might vary. You could transform the names using the shell's built-in parameter substitution if you assume constant field-widths. That's relatively limited in scope.
More interesting would be using character classes in sed:
newname=$(echo "$oldname" | sed -e 's/^\([[:alpha:]]\+\)\([[:digit:]]\+\)_/\1-\2-/')
that is, after a leading alphabetic prefix, add a dash, and then after the digits ending with an underscore, change that to a dash.
Unlike the possible solutions using parameter substitution, this approach allows any (nonzero) length from the alphabetic prefix and digits. So you could have this as input:
ABS1789_2563-01
ABS1789_2563-02
ABS1789_2563-02
ABSOLUTE1789_2563-01
ABSURD1789_2563-02
ABSOLVE1789_2563-02
PREFIX1793939389_2563-02
put that in a script
#!/bin/sh
for oldname in `cat foo4.txt`
do
newname=$(echo "$oldname" | sed -e 's/^\([[:alpha:]]\+\)\([[:digit:]]\+\)_/\1-\2-/')
echo "$oldname ->$newname"
done
giving this output (in a suitable loop):
ABS1789_2563-01 ->ABS-1789-2563-01
ABS1789_2563-02 ->ABS-1789-2563-02
ABS1789_2563-02 ->ABS-1789-2563-02
ABSOLUTE1789_2563-01 ->ABSOLUTE-1789-2563-01
ABSURD1789_2563-02 ->ABSURD-1789-2563-02
ABSOLVE1789_2563-02 ->ABSOLVE-1789-2563-02
PREFIX1793939389_2563-02 ->PREFIX-1793939389-2563-02
If all starts with ABS1789_2563-
for f in ABS*; do mv "$f" ABS-1789-2563-${f:13}; done
Here
ABS-1789-2563-
is simply hard coded under the assumption all your folders starts with ABS1789_2563-.
${f:13}
expands to the end of parameter $f starting from offset 13 - often referred to as substring. In bash Substring Expansion.
See 3.5.3 Shell Parameter Expansion, section:
${parameter:offset} ${parameter:offset:length}
${var:13} evaluates to "the value of the variable var starting at the thirteenth character". So if var were set to qwertyuiopasdfghjkl, ${var:13} would be equivalent to fghjkl.