remove prefix and suffix from the file with mv - linux

I have a directory which contains multiple files. I need to rename these files.
This is how the file names looks like:
snap-file-name-1.txt
snap-file-name-2.txt
snap-file-name-3.txt
I need to remove "snap" and ".txt" from these files.
-file-name-1
-file-name-2
-file-name-3
How do I do that with mv command?

Use sed to manipulate the file name:
ls | while read file; do
mv -- ${file} $(sed -n 's/snap\(.*\).txt/\1/p' <<<${file})
done

With Bash you could do something like this to rename those files:
#!/bin/bash
files=$(find -type f -name 'snap-file-name-*.txt')
for f in $files
do
mv "$f" "$(echo $f | sed -n 's/snap\(.*\).txt/\1/p')"
done

Use rename command with specific regex pattern:
rename 's/snap([-a-z0-9]+)\.txt$/$1/' *.*

Related

How to change extension of certain files? [duplicate]

I want to write a code is shell scripting which will rename all the files of extension .txt in a current directory to extension .c .Suppose my current directory contains some 100 .txt file. This number is not fixed.
for f in *.txt; do echo mv "$f" "${f%.txt}.c"; done
Remove "echo" when you're satisfied it's working. See the bash manual for the meaning of "%" here.
See man rename. You can rename multiple files providing regexp substitution.
rename 's/\.txt$/.c/' *.txt
If you don't have rename in you system, you can use find:
find . -name '*.txt' | while read FILE; do echo mv "$FILE" "$(echo "$FILE" | sed 's/\.txt$/.c/g')"; done
Remove echo when you verify it does what you want.
awk can do this trick too:
kent$ ls *.txt|awk '{o=$0;gsub(/txt$/,"c"); print "mv "o" "$0;}'|sh

Create duplicate file and rename it

I want duplicates of the files with different name.
I am currently trying out these commands before putting them into my bash script.
$ set dir = /somewhere/states
$ find $dir -name "total.txt" -type f | xargs ls -1
/somewhere/states/florida/fixed.fl_Asite_ttl/somewhere/total.txt
/somewhere/states/hawaii/fixed.hi_Bsite_ttl/somewhere/total.txt
/somewhere/states/kentucky/fixed.ky_Asite_ttl/somewhere/total.txt
/somewhere/states/michigan/fixed.mi_Csite_ttl/somewhere/total.txt
/somewhere/states/texas/fixed.tx_Vsite_ttl/somewhere/total.txt
I know I can rename file using something like this, but it isn't exactly what I want:
$ find $dir -name "total.txt" -exec sh -c 'cp {} `dirname {}`/`basename {} `why.xls' \;
/somewhere/states/florida/fixed.fl_Asite_ttl/somewhere/total.txtwhy.xls
/somewhere/states/hawaii/fixed.hi_Bsite_ttl/somewhere/total.txtwhy.xls
/somewhere/states/kentucky/fixed.ky_Asite_ttl/somewhere/total.txtwhy.xls
/somewhere/states/michigan/fixed.mi_Csite_ttl/somewhere/total.txtwhy.xls
/somewhere/states/texas/fixed.tx_Vsite_ttl/somewhere/total.txtwhy.xls
May I know how to copy the files and have the new files in the same dir?
below are the examples.
I want to name the new files as everything behind "fixed." and before "/somewhere" and changing the file extension as well
/somewhere/states/florida/fixed.fl_Asite_ttl/somewhere/fl_Asite_ttl.xls
/somewhere/states/hawaii/fixed.hi_Bsite_ttl/somewhere/hi_Bsite_ttl.xls
/somewhere/states/kentucky/fixed.ky_Asite_ttl/somewhere/ky_Asite_ttl.xls
/somewhere/states/michigan/fixed.mi_Csite_ttl/somewhere/mi_Csite_ttl.xls
/somewhere/states/texas/fixed.tx_Vsite_ttl/somewhere/tx_Vsite_ttl.xls
Update:
/somewhere/states/florida_fixed_ttl/fixed.fl_Asite_ttl/somewhere/total.txt
Probably not the most elegant but this should work:
find . -name total.txt | while read F ; do [[ $F =~ fixed.[^/]* ]] ; N=$(echo $BASH_REMATCH | sed s/fixed\.//) ; echo "cp $F $(dirname $F)/$N.xls" ; done
If you are happy with the output just remove the last echo, i.e. this:
echo "cp $F $(dirname $F)/$N.xls"
to this:
cp "$F" "$(dirname $F)/$N.xls"
Note, if the .txt and .xls contents will always remain the same you can use ln instead of cp -- one file, two names.

How to use sed to change file extensions?

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.
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
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.
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
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.
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
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
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

change *.foo to *.bar in unix one-liner

I am trying to convert all files in a given directory with suffix ".foo" to files containing the same basename but with suffix modified to ".bar". I am able to do this with a shell script and a for loop, but I want to write a one-liner that will achieve the same goal.
Objective:
Input: *.foo
Output: *.bar
This is what I have tried:
find . -name "*.foo" | xargs -I {} mv {} `basename {} ".foo"`.bar
This is close but incorrect. Results:
Input: *.foo
Output: *.foo.bar
Any ideas on why the given suffix is not being recognized by basename? The quotes around ".foo" are dispensable and the results are the same if they are omitted.
Although basename can work on file extensions, using the shell parameter expansion features is easier:
for file in *.foo; do mv "$file" "${file%.foo}.bar"; done
Your code with basename doesn't work because the basename is only run once, and then xargs just sees {}.bar each time.
for file in *.foo ; do mv $file echo $file | sed 's/\(.*\.\)foo/\1bar/' ; done
Example:
$ ls
1.foo 2.foo
$ for file in *.foo ; do mv $file `echo $file | sed 's/\(.*\.\)foo/\1bar/'` ; done
$ ls
1.bar 2.bar
$
for x in $(find . -name "*.foo"); do mv $x ${x%%foo}bar; done
$ for f in *.foo; do echo mv $f ${f%foo}bar; done
mv a.foo a.bar
mv b.foo b.bar
Remove echo when ready.
If you have installed mmv, you can do
mmv \*.foo \#1.bar
.
Why don't you use "rename" instead of scripts or loops.
RHEL: rename foo bar .*foo
Debian: rename 's/foo/bar/' *.foo

Add file extension to files with bash

What is the good way to add file extension ".jpg" to extension-less files with bash?
# Strip .jpg from all filenames
for f in *.jpg; do mv "$f" "${f%.jpg}"; done
# Add .jpg to all filenames (even those with .jpg already)
for f in *; do mv "$f" "$f.jpg"; done
# Add .jpg to all filenames...unless they are already .jpg
for f in *; do case "$f" in *.jpg) echo skipped $f;; *) mv "$f" "$f".jpg; esac; done
# Add .jpg to all filenames...unless they already have a . extension
for f in *; do case "$f" in *.*) echo skipped $f;; *) mv "$f" "$f".jpg; esac; done
You can use rename:
rename 's/(.*)/$1.jpg/' *
Another way - without loops
find . -type f -not -name "*.*" -print0 |\
xargs -0 file |\
grep 'JPEG image data' |\
sed 's/:.*//' |\
xargs -I % echo mv % %.jpg
Breakdown:
find all files without extension
check the file type
filter out only JPG files
delete filetype info
xargs run the "mv" for each file
the above command is for dry run, after it you should remove the "echo" before mv
EDIT
Some people suggesting that here is needed "Wrap path arguments in quotes; avoids argument splitting on paths with spaces".
Usually, this recommendation is true, in this case isn't. Because, here the % is got replaced not by shell expansion but by the xargs internally (directly), so the % will be substituted correctly even with spaces in filenames.
Simple demo:
$ mkdir xargstest
$ cd xargstest
# create two files with spaces in names
$ touch 'a b' 'c d'
$ find . -type f -print
./c d
./a b
# notice, here are spaces in the above paths
#the actual xargs mv WITHOUT quotes
$ find . -type f -print | xargs -I % mv % %.ext
$ find . -type f -print
./a b.ext
./c d.ext
# the result is correct even in case with spaces in the filenames...
Simple,
cd to the directory where your files are and:
for f in *;do mv $f $f.jpg;done
dry run:
rename -n s/$/.jpg/ *
actual renaming:
rename s/$/.jpg/ *
find . | while read FILE; do if [ $(file --mime-type -b "$FILE") == "image/jpeg" ]; then mv "$FILE" "$FILE".jpg; fi; done;
In my case i was not aware of the filetype so i used the mv command with the help of the file command to examine and possibly find the file type. This solution might not be perfect for all files since the file command might not recognize the filetype but it worked mostly good for me.
for f in *; do ext=$(file $f | awk '{print $2;}'); mv -n "$f" "$f.$ext"; done
The use of awk is to strip the second word of the string returned from the command file that is actually the extension.
rename --dry-run * -a ".jpg" # test
* -a ".jpg" # rename
You can use move multiple files. I am a maintainer of this project. The syntax is simple.
mmf files*
It will open your $EDITOR with all files names, or vim by default and you can simply highlight the end of all file names using Ctrl+v+G in vim , save the file,quit and that it , all your files are renamed
Ryan Li
The correct syntax for adding a file extension to multiple files within a directory which do not have a file extension is
find . | while read FILE; do if [[ -n `file --mime-type "$FILE" | grep 'message/rfc822'` ]]; then mv "$FILE" "$FILE".eml; fi; done;

Resources