Is there a way to add a suffix to files where the suffix comes from a list in a text file?

Viewed 42

So currently the searches are coming up with a single word renaming solution, where you define the (static) suffix within the code. I need to rename based on a text based filelist and so -

I have a list of files in /home/linux/test/ :

1000.ext
1001.ext
1002.ext
1003.ext
1004.ext

Then I have a txt file (labels.txt) containing the labels I want to use:

Alpha
Beta
Charlie
Delta
Echo

I want to rename the files to look like (example1):

1000 - Alpha.ext
1001 - Beta.ext
1002 - Charlie.ext
1003 - Delta.ext
1004 - Echo.ext

How would you a script which renames all the files in /home/linux/test/ to the list in example1?

3 Answers

Use paste to loop through the two lists in parallel. Split the filenames into the prefix and extension, then combine everything to make the new filenames.

dir=/home/linux/test
for file in "$dir"/*.ext
do
    read -r label
    prefix=${file%.*} # remove everything from last .
    ext=${file##*.}   # remove everything before last .
    mv "$file" "$prefix - $label.$ext"
done < labels.txt

I originally partly got the request wrong, although this step is still useful, because it gives you the filenames you need.

#!/bin/sh

count=1000
cp labels.txt stack

cat > ed1 <<EOF
1p
q
EOF

cat > ed2 <<EOF
1d
wq
EOF

next () {
[ -s stack ] && main
}

main () {
line="$(ed -s stack < ed1)"
echo "${count} - ${line}.ext" >> newfile
ed -s stack < ed2
count=$(($count+1))
next
}

next

Now we just need to move the files:-

cp newfile stack
for i in *.ext
do
newname="$(ed -s stack < ed1)"
mv -v "${i}" "${newname}"
ed -s stack < ed2
done

rm -v ./ed1
rm -v ./ed2
rm -v ./stack
rm -v ./newfile

On the possibility that you don't have exactly the same number of files as labels, I set it up to cycle a couple of arrays in pseudo-parallel.

$: cat script
#!/bin/env bash
lst=( *.ext )                  # array of files to rename
mapfile -t labels < labels.txt # array of labels to attach
for ndx in ${!lst[@]}          # for each filename's numeric index 
do # assign the new name
   new="${lst[ndx]/.ext/ - ${labels[ndx%${#labels[@]}]}.ext}"
   # show the command to rename the file
   echo "mv \"${lst[ndx]}\" \"$new\"" 
done

$: ls -1 *ext # I added an extra file
1000.ext
1001.ext
1002.ext
1003.ext
1004.ext
1005.ext

$: ./script # loops back if more files than labels
mv "1000.ext" "1000 - Alpha.ext"
mv "1001.ext" "1001 - Beta.ext"
mv "1002.ext" "1002 - Charlie.ext"
mv "1003.ext" "1003 - Delta.ext"
mv "1004.ext" "1004 - Echo.ext"
mv "1005.ext" "1005 - Alpha.ext"

$: ./script > do # use ./script to write ./do
$: ./do          # use ./do to change the names
$: ls -1
'1000 - Alpha.ext'
'1001 - Beta.ext'
'1002 - Charlie.ext'
'1003 - Delta.ext'
'1004 - Echo.ext'
'1005 - Alpha.ext'
do
labels.txt
script

You can just remove the echo to have ./script rename the files there.
I renamed labels to labels.txt to match your example.

If you aren't using bash this will need a call to something like sed or awk. Here's a short awk-based script that will do the same.

$: cat script2
#!/bin/env sh
printf "%s\n" *.ext > files.txt
awk 'NR==FNR{label[i++]=$0}
     NR>FNR{ if (! label[i] ) { i=0 } cmd="mv \""$0"\" \""gensub(/[.]ext/, " - "label[i++]".ext", 1)"\"";
      print cmd;
      # system(cmd);
}' labels.txt files.txt

Uncomment the system line to make it actually do the renames as well.
It does assume your filenames don't have embedded newlines. Let us know if that's a problem.

Related