6

I have to do a sed line (also using pipes in Linux) to change a file extension, so I can do some kind of mv *.1stextension *.2ndextension like mv *.txt *.c. The thing is that I can't use batch or a for loop, so I have to do it all with pipes and sed command.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
heythatsmekri
  • 781
  • 2
  • 8
  • 16

7 Answers7

12

you can use string manipulation

filename="file.ext1"
mv "${filename}" "${filename/%ext1/ext2}"

Or if your system support, you can use rename.

Update

you can also do something like this

mv ${filename}{ext1,ext2}

which is called brace expansion

CS Pei
  • 10,869
  • 1
  • 27
  • 46
  • I wonder if we are allowed to user `rename` ...it is available in most Linux system – CS Pei Oct 03 '13 at 17:19
  • Thanks, but i cant use any batch or script sentence, I just can use my command line, sed and pipes – heythatsmekri Oct 03 '13 at 17:22
  • what exactly your input? what kind of output do you expect? if only `sed` allowed I don't think you can rename a file. – CS Pei Oct 03 '13 at 17:25
  • 2
    @user2113403: `for filename in *.1stextension; do mv "${filename}" "${filename/%1stextension/2ndextension}"; done` will do for a bunch of files. No need for `sed`. – bitmask Oct 03 '13 at 19:44
  • POSIX: `${filename%.ext1}.ext2` – OJFord Jan 14 '17 at 18:59
5

sed is for manipulating the contents of files, not the filename itself. My suggestion:

rename 's/\.ext/\.newext/' ./*.ext

Or, there's this existing question which should help.

Community
  • 1
  • 1
chooban
  • 9,018
  • 2
  • 20
  • 36
4

This may work:

find . -name "*.txt" | 
sed -e 's|./||g' | 
awk '{print "mv",$1, $1"c"}' | 
sed -e "s|\.txtc|\.c|g" > table;
chmod u+x table;
./table

I don't know why you can't use a loop. It makes life much easier :

newex="c";  # Give your new extension
for file in *.*;  # You can replace with *.txt instead of *.*
do 
 ex="${file##*.}";    # This retrieves the file extension
 ne=$(echo "$file" | sed -e "s|$ex|$newex|g"); # Replaces current with the new one
 echo "$ex";echo "$ne";
 mv "$file" "$ne";
done
agc
  • 7,973
  • 2
  • 29
  • 50
iamauser
  • 11,119
  • 5
  • 34
  • 52
3

You can use find to find all of the files and then pipe that into a while read loop:

$ find . -name "*.ext1" -print0 | while read -d $'\0' file
do
   mv $file "${file%.*}.ext2"
done

The ${file%.*} is the small right pattern filter. The % marks the pattern to remove from the right side (matching the smallest glob pattern possible), The .* is the pattern (the last . followed by the characters after the .).

The -print0 will separate file names with the NUL character instead of \n. The -d $'\0' will read in file names separated by the NUL character. This way, file names with spaces, tabs, \n, or other wacky characters will be processed correctly.

David W.
  • 105,218
  • 39
  • 216
  • 337
  • How this is not a loop ? OP doesn't want any loop ! – iamauser Oct 03 '13 at 17:24
  • It's a pipe. As the OP said "_so i have to do it all with **pipes** and sed command_". I'm not sure what the issue the OP was having with `for`, but `for` can be troublesome because of the way it parses the parameters for the loop. Unfortunately, the OP didn't provide much information what they are doing. With more info, I could give a better answer. – David W. Oct 03 '13 at 17:33
  • Agree with you that OP doesn't provide enough information, why not loop ! – iamauser Oct 03 '13 at 17:45
2

You may try following options

Option 1 find along with rename

find . -type f -name "*.ext1" -exec rename -f 's/\.ext1$/ext2/' {} \;

Option 2 find along with mv

find . -type f -name "*.ext1" -exec sh -c 'mv -f $0 ${0%.ext1}.ext2' {} \;

Note: It is observed that rename doesn't work for many terminals

jkshah
  • 11,387
  • 6
  • 35
  • 45
  • @iamauser try using option 2 `mv` if `rename` is not working. Even I am not sure why `rename` doesn't work for many terminals. For me it works in `ubuntu` but not in `RHEL` – jkshah Oct 03 '13 at 17:51
2

Another solution only with sed and sh

printf "%s\n" *.ext1 | 
sed "s/'/'\\\\''/g"';s/\(.*\)'ext1'/mv '\''\1'ext1\'' '\''\1'ext2\''/g' | 
sh

for better performance: only one process created

perl -le '($e,$f)=@ARGV;map{$o=$_;s/$e$/$f/;rename$o,$_}<*.$e>' ext2 ext3
agc
  • 7,973
  • 2
  • 29
  • 50
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36
0

well this should work

mv $file $(echo $file | sed -E -e 's/.xml.bak.*/.xml/g' | sed -E -e 's/.\///g')

output

abc.xml.bak.foobar -> abc.xml
Abhiroj Panwar
  • 485
  • 9
  • 19