30

I need to rename 45 files, and I don't want to do it one by one. These are the file names:

chr10.fasta         chr13_random.fasta  chr17.fasta         chr1.fasta          chr22_random.fasta  chr4_random.fasta  chr7_random.fasta  chrX.fasta
chr10_random.fasta  chr14.fasta         chr17_random.fasta  chr1_random.fasta   chr2.fasta          chr5.fasta         chr8.fasta         chrX_random.fasta
chr11.fasta         chr15.fasta         chr18.fasta         chr20.fasta         chr2_random.fasta   chr5_random.fasta  chr8_random.fasta  chrY.fasta
chr11_random.fasta  chr15_random.fasta  chr18_random.fasta  chr21.fasta         chr3.fasta          chr6.fasta         chr9.fasta         
chr12.fasta         chr16.fasta         chr19.fasta         chr21_random.fasta  chr3_random.fasta   chr6_random.fasta  chr9_random.fasta
chr13.fasta         chr16_random.fasta  chr19_random.fasta  chr22.fasta         chr4.fasta          chr7.fasta         chrM.fasta

I need to change the extension ".fasta" to ".fa". I'm trying to write a bash script to do it:

for i in $(ls chr*)

do

NEWNAME = `echo $i | sed 's/sta//g'`

mv $i $NEWNAME

done

But it doesn't work. Can you tell me why, or give another quick solution?

Thanks!

Slothworks
  • 1,083
  • 14
  • 18
Geparada
  • 2,898
  • 9
  • 31
  • 43

3 Answers3

41

Several mistakes here:

  • NEWNAME = should be without space. Here bash is looking for a command named NEWNAME and that fails.
  • you parse the output of ls. this is bad if you had files with spaces. Bash can build itself a list of files with the glob operator *.
  • You don't escape "$i" and "$NEWNAME". If any of them contains a space it makes two arguments for mv.
  • If a file name begins with a dash mv will believe it is a switch. Use -- to stop argument processing.

Try:

for i in chr*
do
  mv -- "$i" "${i/%.fasta/.fa}"
done

or

for i in chr*
do
  NEWNAME="${i/%.fasta/.fa}"
  mv -- "$i" "$NEWNAME"
done

The "%{var/%pat/replacement}" looks for pat only at the end of the variable and replaces it with replacement.

Benoit
  • 76,634
  • 23
  • 210
  • 236
  • I shouldn't have removed my comment, but I saw you had answered above. Thanks. – nickd Jan 17 '12 at 17:48
  • nice, using `/%` and `--` for `mv`. I would probably include the extension in the `for` loop, `for i in chr*.fasta` – c00kiemon5ter Jan 17 '12 at 17:49
  • Thanks for your complete answer! – Geparada Jan 17 '12 at 17:50
  • Nice use of bash substitution. +1 – jaypal singh Jan 17 '12 at 18:38
  • 1
    @Chris Dodd: taking good habits is though so useful afterwards. – Benoit Jan 17 '12 at 20:07
  • 2
    One man's virtue is another man's vice -- Encouraging the use of spaces in filenames (or files that begin with `-`) is not a good thing. – Chris Dodd Jan 17 '12 at 23:05
  • 1
    Why is it not a good thing? Because programmers don't always correctly handle them? Ask the end users of computer workstations to remove all spaces, dashes, and non-alphanumeric characters from their filenames and spot their reaction :) As programmers it is our job to adapt to the possibilities of the systems we work on. As for files that begin with `-` why couldn't I name a file starting with a negative number for instance? – Benoit Jan 18 '12 at 06:24
  • Very handy, I used it in cygwin on my PC, but I had an issue that SublimeText was saving it as a Windows text file \r\n, then I ran the dos2unix.exe on it and it ran just fine! – Craig London Mar 03 '16 at 21:23
  • Tried to edit my last comment, but ran out of time. Created this Gist of the file -- [link https://gist.github.com/craiglondon/15107556eec481c57b59](https://gist.github.com/craiglondon/15107556eec481c57b59) – Craig London Mar 03 '16 at 21:29
  • 1
    What does `mv --` do? I've found it [elsewhere](https://unix.stackexchange.com/questions/132235/quickest-way-to-rename-files-without-retyping-directory-path) but can't figure out what it does. – Josh Nov 13 '19 at 16:30
  • 2
    @Josh `--` signifies end of option parsing. Therefore, if you have a file named `-i` for example, `mv -- -i …` will work because `-i` will not be interpreted as a switch. – Benoit Feb 11 '20 at 10:22
14
for f in chr*.fasta; do mv "$f" "${f/%.fasta/.fa}"; done
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • althought this would work with the given data, what about spaces in files, or files that contain `.fasta` in their filename and not only as their extension ? many things can go wrong here – c00kiemon5ter Jan 17 '12 at 17:51
  • fixed use of `/%` before I even got to post the above comment ;) – c00kiemon5ter Jan 17 '12 at 17:52
  • Ok, I added the quotes even though they almost certainly aren't needed, given the OP's example. There also aren't likely any spurious periods in the names. – Chris Dodd Jan 17 '12 at 19:28
  • @Chris Dodd: so, now your answer is very similar to mine :) And always quoting is taking good habits. I used to use them lazily and one day came the disaster. – Benoit Jan 17 '12 at 20:09
  • Removed downvote since files with spaces issue is fixed. Always use best practices when teaching others! – jordanm Jan 19 '12 at 04:21
7

If you have the rename command, you can do:

rename .fasta .fa chr*.fasta
dogbane
  • 266,786
  • 75
  • 396
  • 414