Swapping one character in filename with another

I have a file that has the name a_b-c-d-e-f.txt. I would like to take that current name and swap the dashes and underscores so that it becomes a-b_c_d_e_f.txt.

My intuition tells me to try rename or tr, but I’m having issues with this. Here is my current attempt

#!/bin/bash
for i in *.txt; do
  [ -f "$i" ] || break
  newFile=$(echo "$i" | tr '-' '_')
  cp "$i" $newFile
done

With this, I end up with

a_b_c_d_e_f.txt

It’s that part between a-b that should not be changing. Also, that dash is not necessarily always in that place in the filename. For example, it may look like

a-b-c_d-e-f.txt

Or any combination like this. I want them to flip not matter their place in the name.

Asked By: German Barcenas

||
$ echo "a-b_c" | tr '_-' '-_'
a_b-c
Answered By: Tony

Some other options:

  1. your loop but with sed’s rarely used y transliteration command in place of tr ex.

    printf -v newFile "%s" "$(sed 'y/_-/-_/' <<<"$i")"
    
  2. the perl-based rename command, using perl’s built-in tr (no shell loop required)

    rename -n 'tr/_-/-_/' *[-_]*.txt
    

    (remove the -n when you are happy it’s doing the right thing).

Answered By: steeldriver

With rename (manual) just

rename 'y/_-/-_/' *.txt

Here is more info about y/(transliteration). Also check this related post about rename.

Answered By: Pablo Bianchi
for v in *.txt
do
    newname=`echo $v | tr '_-' '-_'`
    mv $v $newname
done

I found this to work. This was a combo of my post and Tony’s response.

Answered By: German Barcenas