mkdir with sed in bash script - bash

I want to create directories which names should correspond to a list of zipped files in the parent directory. Additionally I want to get rid of the file extension in the resulting name of the directory.
e.g. archive01.gz should result in a directory with name archive01
My script so far:
#!/bin/bash
for file in *.gz; do
echo $file | sed 's/.gz//' | mkdir
done
The error message is:
mkdir: missing operand
However,
echo $file | sed 's/.gz//'
results in the correct name for the directory. How do I pipe it to mkdir?

A better way to do this would be to use parameter substitution instead of a pipe/subshell:
#!/bin/bash
for file in *.gz; do
mkdir ${file%.gz}
done

Try this,
#!/bin/bash
for file in *.gz; do
echo "$file" | sed 's/\.gz//' | xargs mkdir
done

mkdir doesn't work with pipes. Try the following:
mkdir `echo $file | sed 's/.gz//'`
The ` evaluates and then replaces it with the answer. It's called command substitution and alternatively could also be written as:
mkdir $(echo $file | sed 's/.gz//')

You can use command substitution as
#!/bin/bash
for file in *.gz; do
mkdir $(echo $file | sed 's/.gz//')
done
OR
#!/bin/bash
for file in *.gz; do
mkdir `echo $file | sed 's/.gz//'`
done

Related

Move files according to number in filename

I am trying to move files in folders according to a number in their names.
Files are names like fooNNN_bar.txt I would like to organise them like /NNN/fooNNN_bar.txt
Here is what I have for now. It prints me the folder each file would have to move to. I'm not sure how to collect the number to add it into a mv command. Is this even the correct way to do it?
#!/bin/bash
for filename in foo*.txt;
do
echo "${filename}" | grep -Eo '[0-9]{1,4}';
done
Assuming your grep works as you want:
#!/bin/bash
for filename in foo*.txt; do
num=$(echo "${filename}" | grep -Eo '[0-9]{1,4}')
mkdir -p "$num"
mv "$filename" "$num"
done

Bash script to remove chars from all filenames in folder

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

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

Batch renaming using shell script

I have a folder with files named as
input (1).txt
input (2).txt
input (3).txt
...
input (207).txt
How do I rename them to
input_1.in
input_2.in
input_3.in
...
input_207.in
I am trying this
for f in *.txt ; do mv $f `echo $f | sed -e 's/input\ (\(\d*\))\.txt/input_\1.in/'` ; done
But it gives me
mv: target `(100).txt' is not a directory
mv: target `(101).txt' is not a directory
mv: target `(102).txt' is not a directory
...
Where did I go wrong?
I have put in the quotes now, but I get this now
mv: `input (90).txt' and `input (90).txt' are the same file
It is somehow trying to rename the file to the same name. How is that happening?
That is because bash for split the element with space ' ' so you are commanding it to move 'input' to '(1)'.
The way to solve this is to tell bash to split by new line using IFS variable.
Like this:
IFS=$'\n'
Then do your command.
However, I suggest you to use find to do this instead using -exec command.
For example:
find *.txt -exec mv "{}" `echo "{}" | sed -e 's/input\ (\([0-9]*\))\.txt/input_\1.in/'` \;
NOTE: I write this from memory and I did test this so let try and adjust it.
Hope this helps.
You're forgetting to quote your arguments.
... mv "$f" "$(echo "$f" | ... )" ; done
no need to call external commands
#!/bin/bash
shopt -s nullglob
shopt -s extglob
for file in *.txt
do
newfile="${file//[)]/}"
newfile="${file// [(]/_}"
mv "$file" "${newfile%.txt}.in"
done
As you've already fixed, you need to quote the $f argument to mv.
As to your second problem, sed doesn't support \d. You could use [0-9] instead.
for f in *.txt ; do mv "$f" `echo $f | sed -e 's/input\ (\(\d*\))\.txt/input_\1.in/'` ; done
If you have GNU Parallel http://www.gnu.org/software/parallel/ installed you can do this:
seq 1 207 | parallel -q mv 'input ({}).txt' input_{}.in
Watch the intro video for GNU Parallel to learn more:
http://www.youtube.com/watch?v=OpaiGYxkSuQ

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