I have a file with multiple occurrences of the expression ".mp3". I want the first occurrence to become "1.mp3", the second occurrence to become "2.mp3", and so on.

It would be something like awk '/ mp3 / NR' file

My file:

line 1
wget .mp3 url
line 2
wget .mp3


I haven't got any results

  • Asked and answered at stackoverflow.com/q/57847550/1745001 - please don't multi-post. – Ed Morton Sep 9 '19 at 16:00
  • @EdMorton, Thankful. Now that the question has been answered I will delete the replicated question there. I do not know if a multi-post is wrong, if you can point this out in the guidelines of this forum I am grateful that I can know the limits of my actions :) – Diego Bnei Noah Sep 10 '19 at 14:07
  • I'm not going to look for it in guidelines for this forum - not multi-posting has been part of all online forums etiquette since the 1990s. Just google netiquette multiposting – Ed Morton Sep 10 '19 at 14:15
$ awk -v i=1 '/ \.mp3/ {sub(/ \.mp3/," "i++".mp3",$0)};1' input.txt
line 1
wget 1.mp3 url
line 2
wget 2.mp3

If the numerals in the wget URL are meant to be zero-padded, you can use awk's sprintf() to format i with leading zeroes. For example:

$ awk -v i=1 '/ \.mp3/ {sub(/ \.mp3/," "sprintf("%03i",i++)".mp3",$0)};1' input.txt
line 1
wget 001.mp3 url
line 2
wget 002.mp3

You could also combine sprintf() with wget's -O (--output-document) option to save the downloaded files with zero-padded filenames, so they sort correctly (e.g. 01,02,03,...10 instead of 1,10,2,3,...)

$ awk -v i=1 '/ \.mp3/ {sub(/ \.mp3/," "i".mp3 -O "sprintf("%03i",i++)".mp3",$0)};1' input.txt
line 1
wget 1.mp3 -O 001.mp3 url
line 2
wget 2.mp3 -O 002.mp3

All of the above one-liners will output to stdout. To overwrite the original, redirect to a new file and either mv it or overwrite the original.

awk -v i=1 '/ \.mp3/ {sub(/ \.mp3/," "i++".mp3",$0)};1' orig.txt > new.txt

and then either:

mv new.txt orig.txt

This will replace orig.txt with a new file created with the permissions specified by the current umask value. It may also have a new owner and/or group (depending on who runs it, and what their default group is). It will also have a new inode number, breaking any hard-links that might exist.

Most programs that have an "in-place edit" option (e.g. sed -i or perl -i) do this. In most cases, this is fine because it's being run by the same user with the same umask as the original file's owner, and few files have multiple hard links.


cat new.txt > orig.txt
rm new.txt

This will overwrite the contents of orig.txt with the contents of new.txt, and then delete new.txt. orig.txt will have the same inode, owner, group, and permissions as before.


Try this,

while [ "$( grep -o ' .mp3' file)" != "" ];
 sed -i "0,/ .mp3/ s/ .mp3/ $i.mp3/" file
 i=`expr $i + 1`;
  • Works but a wee bit more complex and probably slower than cas' awksolution which by itself (tx awk!) only ever applies where the record matches. No need for the while "Is there a match?" test in that case. Anyway, +1 on didactic grounds and because the answer certainly does not deserve a downvote ;-) – Cbhihe Sep 9 '19 at 9:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.