Append number to filenames when flattening directory structure on Linux - linux

I have a directory structure that looks like this:
/a/f.xml
/b/f.xml
/c/f.xml
/d/f.xml
What I want to do is copy all the xml files into one directory like this:
/e/f_0.xml
/e/f_1.xml
/e/f_2.xml
/e/f_3.xml
How can I do that efficiently on the Linux shell?

let count=0
for file in $(ls $dir)
do
mv $file $newdir/${file%%.*}_$count.${file##*.}
let count=count+1
done

#!/bin/bash
COUNTER=0;
for i in */f.xml;
do
BASE=`expr "$i" : '.*/\(.*\)\..*'`;
EXT=`expr "$i" : '.*/.*\.\(.*\)'`;
mv "$i" e/"$BASE"_"$COUNTER"."$EXT";
COUNTER=`expr $COUNTER + 1`
done;

#!/bin/bash
for file in /{a,b,c,d}/f.xml
do
name=${file##*/}
name=${name%.xml}
((i++))
echo mv "$file" "/destination/${name}_${i}.xml"
done
bash 4.0 (for recursive)
shopt -s globstar
for file in /path/**/f.xml
do
name=${file##*/}
name=${name%.xml}
((i++))
echo mv "$file" "/destination/${name}_${i}.xml"
done

Related

Convert nth character of all filenames in a directory to uppercase in bash

For files like :
_aaa.txt
_bbb.txt
_ccc.txt
I want to convert them to :
_aAa.txt
_bBb.txt
Any idea how to do this ?
In plain bash, using only shell parameter expansions to perform the conversion:
#!/bin/bash
n=3
for file in *; do
[[ -f $file ]] || continue
suffix=${file:n-1}
mv -i "$file" "${file:0:n-1}${suffix^}"
done
Check the output of the following
#!/bin/bash
for filename in *; do
newname=$(sed 's/./\U&/3' <<< "$filename")
echo "$filename --> $newname"
# mv $filename $newname
done
Then remove the #, if the filename printed is correct
If rename command is available, please try:
rename 's/^(..)(.)/$1\U$2/' *.txt

How do I copy files at same location ending with "*100000.prm" with different name "*full.prm" in linux?

#!/bin/bash
for FILE in *1000000.wgt; do
BASE=${FILE%1000000.wgt}
[[ -e $BASE.trs && -e $BASE.1000000.wgt ]] && cp "$FILE" "$BASE.trs" "$BASE.wav" /some/dir
done
This script does what you need according to your commment.
eg: 'xyz_100000.prm' is to be copied with name 'xyz_full.prm' at the same location.
#!/bin/sh
IFS=$'\n'
for FILE in *1000000.prm; do
new_name=$(echo "$FILE" | sed "s/1000000.prm$/full.prm/")
cp "$FILE" "$new_name"
done
Demonstration:
➜ ls
a1000000.prm b1000000.prm copy.sh
➜ ./copy.sh
➜ ls
afull.prm bfull.prm copy.sh
I'd suggest this:
for i in *1000000.prm; do mv $i ${i%1000000.prm}full.prm; done
Read Parameter expansion section from bash man page.

Change filenames in a specific folder through bash

I have a folder FOLDER1 with different files in it.
I have several files in the folder with an extension .png
I would like to change the filename of all the files with extension .png with a bash script. I tried to write one but I still didn't arrive to have what I want.
#!/bin/bash
# make sure you always put $f in double quotes to avoid any nasty surprises i.e. "$f"
i=0
for f in *.png
do
echo "${i}Processing $f file..."
i+=1;
echo ${i}
# rm "$f"
done
At the end of the script I would like to have all the files named like:
c-1.png
c-2.png
c-3.png
...
...
...
Could you help me?
Thanks
First note that:
i+=1
is string addition. What you're doing is 0,01,011,0111.... You need:
((++i))
Next you need to split your file name, one way if "." appears only once:
base=$(echo $f | cut -d. -f1)
and finally move:
mv $f ${base}-${i}.png
Sorry, I found my solution .
This code is working perfectly.
#!/bin/bash
# make sure you always put $f in double quotes to avoid any nasty surprises i.e. "$f"
i=0
for f in *.png
do
echo "$i Processing $f file..."
i=$((i+1))
mv $f "c-"$i.png
#echo ${i}
done
#!/bin/bash
i=0
for f in *.png
do
echo "${i}Processing $f file..."
i=$((i + 1))
newname="c-${i}.png"
mv "$f" $newname
done

Creating a pathname to check a file doesn't exist there / Permission denied error

Hello from a Linux Bash newbie!
I have a list.txt containing a list of files which I want to copy to a destination($2). These are unique images but some of them have the same filename.
My plan is to loop through each line in the text file, with the copy to the destination occurring when the file is not there, and a mv rename happening when it is present.
The problem I am having is creating the pathname to check the file against. In the code below, I am taking the filename only from the pathname, and I want to add that to the destination ($2) with the "/" in between to check the file against.
When I run the program below I get "Permission Denied" at line 9 which is where I try and create the path.
for line in $(cat list.txt)
do
file=$[ basename $line ]
path=$[ $2$file ]
echo $path
if [ ! -f $path ];
then
echo cp $line $2
else
echo mv $line.DUPLICATE $2
fi
done
I am new to this so appreciate I may be missing something obvious but if anyone can offer any advice it would be much appreciated!
Submitting this since OP is new in BASH scripting no good answer has been posted yet.
DESTINATION="$2"
while read -r line; do
file="${line##*/}"
path="$2/$file"
[[ ! -f $path ]] && cp "$line" "$path" || mv "$line" "$path.DUP"
done < list.txt
Don't have logic for counting duplicates at present to keep things simple. (Which means code will take care of one dup entry) As an alternative you get uniq from list.txt beforehand to avoid the duplicate situation.
#anubhava: Your script looks good. Here is a small addition to it to work with several dupes.
It adds a numer to the $path.DUP name
UniqueMove()
{
COUNT=0
while [ -f "$1" ]
do
(( COUNT++ ))
mv -n "$1" "$2$COUNT"
done
}
while read -r line; do
file="${line##*/}"
path="$2/$file"
[[ ! -f $path ]] && cp "$line" "$path" || UniqueMove "$line" "$path.DUP"
done < list.txt

printing folder names in bash

This piece of bash code, shows no folder name while there exists many folders.
#!/bin/bash
for file in .; do
if [ -d $file ]; then
echo $file
fi
done
the output is only .
Can you explain why?
it reads . as an array of size one and prints it for you. use something like this instead:
for file in `ls`; do
if [ -d $file ]; then
echo $file
fi
done

Resources