Bash script to remove chars from all filenames in folder - bash

I have a folder with few images, all have the same name format:
some-random-name-min.jpg
another-random-name-min.jpg
and-another-random-name-min.jpg
I want to strip the last -min so following this answer
I tried this bash script:
#!/bin/bash
for filename in /home/al/domus-images/portfolio/white snow/*.jpg; do
mv $filname $(echo $filename | sed -e 's/....\.jpg$//');
done
but after running the script nothing happened..any idea what am I missing here?
Thanks

You can use find command to list the files and then to remove -min from file name follow below script.
for filename in `find "/home/al/domus-images/portfolio/white snow/" -name "*.jpg"`;
do
mv $filname $(echo $filename | sed 's/-min.jpg$/.jpg/');
done
This remove last "-min" from file name.

this could be an idea:
#!/bin/bash
for filename in *\-min.jpg
do
newFile=$(echo $filename |sed "s/\-min//g")
printf "before\t:filename[$filename]\tnewFile[$newFile]\n"
mv $filename $newFile
printf "after\t:filename[$filename]\tnewFile[$newFile]\n"
done
output
[shell] ➤ ./myMove
before :filename[and-another-random-name-min.jpg] newFile[and-another-random-name.jpg]
after :filename[and-another-random-name-min.jpg] newFile[and-another-random-name.jpg]
before :filename[another-random-name-min.jpg] newFile[another-random-name.jpg]
after :filename[another-random-name-min.jpg] newFile[another-random-name.jpg]
before :filename[some-random-name-min.jpg] newFile[some-random-name.jpg]
after :filename[some-random-name-min.jpg] newFile[some-random-name.jpg]
this *\-min.jpg is just to be sure to get only the file you need

This might be what you're looking for
#!/bin/bash
for filename in /home/al/domus-images/portfolio/white snow/*-min.jpg
do
mv ${filename} ${filename//-min.jpg/.jpg}
done

Can't get it simpler than this.
rename 's/\-min.jpg$/.jpg/' *-min.jpg

Related

remove substring from filename

I have files with name of the form "NAME-xxxxxx.tedx" and I want to remove the "-xxxxxx" part. The x are all digits.
The regex "\-[0-9]{1,6}" matches the substring, but I have no idea how to remove it from the filename.
Any idea how I can do that in the shell?
If you have the perl version of the rename command installed, you could try:
rename 's/-[0-9]+//' *.tedx
Demo:
[me#home]$ ls
hello-123.tedx world-23456.tedx
[me#home]$ rename 's/-[0-9]+//' *.tedx
[me#home]$ ls
hello.tedx world.tedx
This command is smart enough to not rename files if it means overwriting an existing file:
[me#home]$ ls
hello-123.tedx world-123.tedx world-23456.tedx
[me#home]$ rename 's/-[0-9]+//' *.tedx
world-23456.tedx not renamed: world.tedx already exists
[me#home]$ ls
hello.tedx world-23456.tedx world.tedx
echo NAME-12345.tedx | sed "s/-[0-9]*//g"
will give NAME.tedx. So you can use a loop and move the files using mv command:
for file in *.tedx; do
newfile=$(echo "$file" | sed "s/-[0-9]*//g")
mv "$file" $newfile
done
If you want to use just the shell
shopt -s extglob
for f in *-+([0-9]]).tedx; do
newname=${f%-*}.tedx # strip off the dash and all following chars
[[ -f $newname ]] || mv "$f" "$newname"
done

For files in directory, only echo filename (no path)

How do I go about echoing only the filename of a file if I iterate a directory with a for loop?
for filename in /home/user/*
do
echo $filename
done;
will pull the full path with the file name. I just want the file name.
If you want a native bash solution
for file in /home/user/*; do
echo "${file##*/}"
done
The above uses Parameter Expansion which is native to the shell and does not require a call to an external binary such as basename
However, might I suggest just using find
find /home/user -type f -printf "%f\n"
Just use basename:
echo `basename "$filename"`
The quotes are needed in case $filename contains e.g. spaces.
Use basename:
echo $(basename /foo/bar/stuff)
Another approach is to use ls when reading the file list within a directory so as to give you what you want, i.e. "just the file name/s". As opposed to reading the full file path and then extracting the "file name" component in the body of the for loop.
Example below that follows your original:
for filename in $(ls /home/user/)
do
echo $filename
done;
If you are running the script in the same directory as the files, then it simply becomes:
for filename in $(ls)
do
echo $filename
done;
You can either use what SiegeX said above or if you aren't interested in learning/using parameter expansion, you can use:
for filename in $(ls /home/user/);
do
echo $filename
done;
if you want filename only :
for file in /home/user/*; do
f=$(echo "${file##*/}");
filename=$(echo $f| cut -d'.' -f 1); #file has extension, it return only filename
echo $filename
done
for more information about cut command see here.

How can I manipulate file names using bash and sed?

I am trying to loop through all the files in a directory.
I want to do some stuff on each file (convert it to xml, not included in example), then write the file to a new directory structure.
for file in `find /home/devel/stuff/static/ -iname "*.pdf"`;
do
echo $file;
sed -e 's/static/changethis/' $file > newfile +".xml";
echo $newfile;
done
I want the results to be:
$file => /home/devel/stuff/static/2002/hello.txt
$newfile => /home/devel/stuff/changethis/2002/hello.txt.xml
How do I have to change my sed line?
If you need to rename multiple files, I would suggest to use rename command:
# remove "-n" after you verify it is what you need
rename -n 's/hello/hi/g' $(find /home/devel/stuff/static/ -type f)
or, if you don't have rename try this:
find /home/devel/stuff/static/ -type f | while read FILE
do
# modify line below to do what you need, then remove leading "echo"
echo mv $FILE $(echo $FILE | sed 's/hello/hi/g')
done
Are you trying to change the filename? Then
for file in /home/devel/stuff/static/*/*.txt
do
echo "Moving $file"
mv "$file" "${file/static/changethis}.xml"
done
Please make sure /home/devel/stuff/static/*/*.txt is what you want before using the script.
First, you have to create the name of the new file based on the name of the initial file. The obvious solution is:
newfile=${file/static/changethis}.xml
Second you have to make sure that the new directory exists or create it if not:
mkdir -p $(dirname $newfile)
Then you can do something with your file:
doSomething < $file > $newfile
I wouldn't do the for loop because of the possibility of overloading your command line. Command lines have a limited length, and if you overload it, it'll simply drop off the excess without giving you any warning. It might work if your find returns 100 file. It might work if it returns 1000 files, but it might fail if your find returns 1000 files and you'll never know.
The best way to handle this is to pipe the find into a while read statement as glenn jackman.
The sed command only works on STDIN and on files, but not on file names, so if you want to munge your file name, you'll have to do something like this:
$newname="$(echo $oldname | sed 's/old/new/')"
to get the new name of the file. The $() construct executes the command and puts the results of the command on STDOUT.
So, your script will look something like this:
find /home/devel/stuff/static/ -name "*.pdf" | while read $file
do
echo $file;
newfile="$(echo $file | sed -e 's/static/changethis/')"
newfile="$newfile.xml"
echo $newfile;
done
Now, since you're renaming the file directory, you'll have to make sure the directory exists before you do your move or copy:
find /home/devel/stuff/static/ -name "*.pdf" | while read $file
do
echo $file;
newfile="$(echo $file | sed -e 's/static/changethis/')"
newfile="$newfile.xml"
echo $newfile;
#Check for directory and create it if it doesn't exist
$dirname=$(dirname "$newfile")
if [ ! -d "$dirname" ]
then
mkdir -p "$dirname"
fi
#Directory now exists, so you can do the move
mv "$file" "$newfile"
done
Note the quotation marks to handle the case there's a space in the file name.
By the way, instead of doing this:
if [ ! -d "$dirname" ]
then
mkdir -p "$dirname"
fi
You can do this:
[ -d "$dirname"] || mkdir -p "$dirname"
The || means to execute the following command only if the test isn't true. Thus, if [ -d "$dirname" ] is a false statement (the directory doesn't exist), you run mkdir.
It's a fairly common shortcut when you see shell scripts.
find ... | while read file; do
newfile=$(basename "$file").xml;
do something to "$file" > "$somedir/$newfile"
done
OUTPUT="$(pwd)";
for file in `find . -iname "*.pdf"`;
do
echo $file;
cp $file $file.xml
echo "file created in directory = {$OUTPUT}"
done
This will create a new file with name whatyourfilename.xml, for hello.pdf the new file created would be hello.pdf.xml, basically it creates a new file with .xml appended at the end.
Remember the above script finds files in the directory /home/devel/stuff/static/ whose file names match the matcher string of the find command (in this case *.pdf), and copies it to your present working directory.
The find command in this particular script only finds files with filenames ending with .pdf If you wanted to run this script for files with file names ending with .txt, then you need to change the find command to this find /home/devel/stuff/static/ -iname "*.txt",
Once I wanted to remove trailing -min from my files. i.e. wanted alg-min.jpg to turn into alg.jpg. so after some struggle, managed to figure something like this:
for f in *; do echo $f; mv $f $(echo $f | sed 's/-min//g');done;
Hope this helps someone willing to REMOVE or SUBTITUDE some part of their file names.

Bash command to remove leading zeros from all file names

I have a directory with a bunch of files with names like:
001234.jpg
001235.jpg
004729342.jpg
I want to remove the leading zeros from all file names, so I'd be left with:
1234.jpg
1235.jpg
4729342.jpg
I've been trying different configurations of sed, but I can't find the proper syntax. Is there an easy way to list all files in the directory, pipe it through sed, and either move or copy them to the new file name without the leading zeros?
for FILE in `ls`; do mv $FILE `echo $FILE | sed -e 's:^0*::'`; done
sed by itself is the wrong tool for this: you need to use some shell scripting as well.
Check Rename multiple files with Linux page for some ideas. One of the ideas suggested is to use the rename perl script:
rename 's/^0*//' *.jpg
In Bash, which is likely to be your default login shell, no external commands are necessary.
shopt -s extglob
for i in 0*[^0]; do mv "$i" "${i##*(0)}"; done
Maybe not the most elegant but it will work.
for i in 0*
do
mv "${i}" "`expr "${i}" : '0*\(.*\)'`"
done
Try using sed, e.g.:
sed -e 's:^0*::'
Complete loop:
for f in `ls`; do
mv $f $(echo $f | sed -e 's:^0*::')
done
I dont know sed at all but you can get a listing by using find:
find -type f -name *.jpg
so with the other answer it might look like
find . -type f -name *.jpg | sed -e 's:^0*::'
but i dont know if that sed command holds up or not.
Here's one that doesn't require sed:
for x in *.jpg ; do let num="10#${x%%.jpg}"; mv $x ${num}.jpg ; done
Note that this ONLY works when the filenames are all numbers. You could also remove the leading zeros using the shell:
for a in *.jpg ; do dest=${a/*(0)/} ; mv $a $dest ; done
In Bash shell you can do:
shopt -s nullglob
for file in 0*.jpg
do
echo mv "$file" "${file##*0}"
done

Strip Characters Before Period If Filename Has Prefix in Bash

I have a directory that looks like this:
pages/
folder1/
folder1.filename1.txt
folder1.filename2.txt
folder2/
folder2.filename4.txt
folder2.filename5.txt
folder3/
filename6.txt
I want it to look like this:
pages/
folder1/
filename1.txt
filename2.txt
folder2/
filename3.txt
filename4.txt
folder3/
filename5.txt
With ls * | sed -e s/^[^.]*.// > /tmp/filenames.txt I get a file containing:
filename1.txt
filename2.txt
filename3.txt
filename4.txt
txt
How can I tell sed to ignore filenames of the form [filename].[suffix] and only look at filenames of the form [foldername].[filename].[suffix]?
The final script (as pointed out, the find command would simplify things, but this worked):
for folder in $(ls .)
do
if test -d $folder
then
pushd $folder
ls * | sed 's/.*\.\(.*\..*\)/\1/' > /tmp/filenames.txt
ls * > /tmp/current.txt
exec 3</tmp/current.txt
exec 4</tmp/filenames.txt
while read file <&3; read name <&4;
do
mv "$file" "$name"
done
rm /tmp/current.txt
rm /tmp/filenames.txt
popd
else
echo $folder "not a directory"
fi
done
exit 0
This page is now a community wiki. You can add more elegant solutions below:
for folder in $(ls .)
do
something better
Give this a try:
sed 's/.*\.\(.*\..*\)/\1/'
You should really use find then you wouldn't need the check for "-d folder" or the temp file and execs or the while loop.
You can avoid the temporary file by using process substition:
while read line
do
echo $line
done < <(ls)
Another item of interest: your system may already have a Perl script called rename or prename which will rename files using a regular expression.
You don't need to use sed:
ls * > /tmp/current.txt
exec 3</tmp/current.txt
while read file <&3;
do
replacement=${file#${folder}.}
if [ "$replacement" != "txt" ] ; then
mv "$file" "$replacement"
fi
done
use the following regex:
/\A(.\*?\\.){2,2}.+\Z/

Resources