How to rename photos using information from csv file - bash

I am new to unix and could really use your help.
I want to rename a lot of photographs so they correspond with codes of items that are on the picture. I have a .csv file that has the original .jpg name and then the codes I want the photos to be renamed to, following in consecutive columns. For example:
IMG_1234.JPG,AB001,AB003,AB004
IMG_1345.JPG,AB011,AB012,AB013,AB014,AB015
IMG_1456.JPG,AB112
IMG_1678.JPG,AB125,AB126
So I want IMG_1234.JPG copied 3 times and renamed to AB001, AB003, and AB004 etc.
I know I need a script and that I can copy and rename files, but I can't figure out how to make a script run through the csv file and copy & rename the .jpg to the names following until an empty cell and then move on to the next row and copy & rename that .jpg etc etc.
I hope my question is clear and I apologize for my limited knowledge.
Thanks in advance!
edit: The image names have directories (with spaces) in front of them as the photographs are in different folders. For example:
./Photos sorted/Samples1-100/IMG_1134.JPG

This should do what you want. The filename of the csv file is given as parameter to the script. You might adjust the paths inside the copy command, currently everything must be in the same directory. If you are using this on a mac or linux, you can also use "ln -s" instead if "cp" to create a symbolic link to the original file to save disk space.
CSVFILE=$1
cat $CSVFILE |\
while read LINE; do
SPLIT=`echo $LINE | tr "," " "`
FIRST=0
for NAME in $SPLIT; do
if [ $FIRST -eq 0 ]; then
SRCNAME=$NAME
else
DSTNAME=$NAME
cp ${SRCNAME}.jpg ${DSTNAME}.jpg
fi
((FIRST++))
done
done

Related

How do I append the contents of numerous files to a single file?

I have 44 RTF files (file1.rtf, file2.rtf, ..., file44.rtf) and I need to combine them all into a single file (either file1.rtf or a new file altogether).
I understand that the way to combine the contents of two files is like this:
cat file2.rtf >> file1.rtf
This example appends the contents of file2.rtf into file1.rtf.
I also understand that I need to iterate through the files, which I can achieve like this:
for file in *.rtf;
do
# do something;
done
As such, I have this which appears to do the job:
#!/bin/bash
for file in *.rtf;
do
cat $file >> "../combined.rtf";
echo "File $file added."
done
But there is an issue: when I run cat ../combined.rtf I see the combined documents but when I run open ../combined.rtf it only shows me the contents of file1.rtf (in LibreOffice Writer).
Where have I gone wrong?

How to recursively rename all files and folder including specific part of the filename with Windows Bash?

This has to be a duplicate but I have read and tried at least a dozen of Q&As here on SO, and I cannot get any of them working for my case.
Really hope this won't result in downvotes because of it.
So I'm on Windows (10) and have a Bash terminal that I want to use for my task. The MINGW64 one I downloaded when I started working with Git.
I would prefer the solution with this program, but will be perfectly happy with one in Command Prompt Terminal or even PowerShell.
I created a TemplateApp which is in C:\Apps\TemplateApp folder which has multiple folders and subfolders named TemplateApp or TemplateApp.something as well as a lot of files that have TemplateApp as a part of their name.
Could be:
TemplateApp.ext
TemplateApp.something.ext
something.TemplateApp.something.ext
Then I copied the uppermost folder to C:\Apps\TemplateApp - Copy and in turn renamed it to C:\Apps\ProductionApplication.
Now for the love of whomever, I cannot make any of the scripts I found on SO to work for my case, ie. to rename all the above mentioned files and folders by replacing TemplateApp with ProductionApplication.
Here is a bash function I wrote that I think does very much like what you are wanting to do.
function func_CreateSourceAndDestination() {
#
for (( i = 0 ; i < ${#files_syncSource[#]} ; i++ )) ; do
files_syncDestination[${i}]="${files_syncSource[${i}]#${directory_MusicLibraryRoot_source}}"
file_destinationPath="$( dirname -- "${directory_PMPRoot_destination}${files_syncDestination[${i}]}" )"
if [ ! -d "${file_destinationPath}" ] ; then
mkdir -p "${file_destinationPath}"
fi
rsync -rltDvPmz "${files_syncSource[${i}]}" "${directory_PMPRoot_destination}${files_syncDestination[${i}]}"
done
}
In my case I'm feeding into rsync for a source and a destination. I'm pulling all the file paths from an array that has been split into path segments. I have to make certain character substitutions for FAT and NTFS file systems. I do this recursively.
files_syncDestination[${i}]="${files_syncDestination[${i}]//\:/__}"
That's the magic. I load a new array with the character substituted. You could do the same with a loaded variable including your phrases for change.
files_syncDestination[${i}]="${files_syncDestination[${i}]//${targetPhrase}/${subPhrase}}"
After that change in the function, you could use rsync or cp or mv as you prefer to go from your source array to your destination array.
(The double-slash in the substitution makes the substitution global.)

Naming a file with a variable in a shell script

I'm writing a unix shell script that sorts data in ten subdirectories (labelled 1-10) of the home directory. In each subdirectory, the script needs to rename the files hehd.output and fort.hehd.time, as well as copy the file hehd.data to a .data file with a new name.
What I'd like it to do is rename each of these files in the following format:
AA.BB.CC
Where
AA = a variable in the hehd.data file within the subdirectory containing the file
BB = the name of the subdirectory containing the file (1-10)
CC = the original file name
Each subdirectory contains an hehd.data file, and each hehd.data file contains the string ij0=AA, where AA represents the variable I want to use to rename the files in the same subdirectory.
For example: When run, the script should search /home/4/hehd.data for the string ij0=2, then move /home/4/hehd.output to /home/4/2.4.hehd.output.
I'm currently using the grep command to have the script search for the string ij0=* and copy it to a new text file within the subdirectory. Next, the string ij0= is deleted from the text file, and then its contents are used to rename all target files in the same subdirectory. The last line of the shell script deletes the text file.
I'm looking for a better way to accomplish this, preferably such that all ten subdirectories can be sorted at once by the same script. My script seems incredibly inefficient, and doesn't do everything that I want it to by itself.
How can I improve this?
Any advice or suggestions would be appreciated; I'm trying to become a better computer user and that means learning better ways of doing things.
Try this:
fromdir=/home
for i in {1..10};do
AA=$(sed 's/ij0=\([0-9]*\)/\1/' "$fromdir/$i/hehd.data")
BB="$i"
for f in "$fromdir/$i/"*;do
CC="${f##*/}"
if [[ "$CC" = "hehd.data" ]]; then
echo cp "$f" "$fromdir/$i/$AA.$BB.$CC"
else
echo mv "$f" "$fromdir/$i/$AA.$BB.$CC"
fi
done
done
It loops over directories using Bash sequence {1..10].
In each directory, with the sed command the ij0 value is assigned to AA variable, the directory name is assigned to BB.
In the file loop, if the file is hehd.data it's copied, else it's renamed with the new name.
You can remove the echo before cp and mv commands if the output meets your needs.

Append part of folder name to all .gz within

I have a folder of data folders with the following structure:
sampleName1-randomNumbers/subfolder1/subfolder2/subfolder3/data1.gz
sampleName1-randomNumbers/subfolder1/subfolder2/subfolder3/data2.gz
sampleName2-randomNumbers/subfolder1/subfolder2/subfolder3/data1.gz
I want to modify all the data.gz within each sample folder by appending the sample name but not the random numbers to get:
sampleName1-randomNumbers/subfolder1/subfolder2/subfolder3/sampleName1_data1.gz
sampleName1-randomNumbers/subfolder1/subfolder2/subfolder3/sampleName1_data2.gz
sampleName2-randomNumbers/subfolder1/subfolder2/subfolder3/sampleName2_data1.gz
It seems like this should be a simple mv for loop but I haven't been able to figure out how to pull part of a folder name using basename.
for i in */Data/Intensities/BaseCalls/*.gz; do mv $i "fastq""/"${i%%-*}"."`basename $i`; done
I couldn't figure out how to make the files stay in their original folder but for my purposes it works to have all the files go to a new folder ("fastq")
I suppose the "sampleName" part doesn't include dashes. In that case, use the standard pattern removal expansion: %%. That is, suppose your full path (relative to directory root) is stored in $path, just do ${path%%-*} to extract the "sampleName" part. Search for %% in the Bash Reference Manual for more details. As a simple example:
> path=sampleName1-randomNumbers/subfolder1/subfolder2/subfolder3/data1.gz
> echo ${path%%-*}
sampleName1
Otherwise, you could also use more advanced substring extraction based on regex. See BashFAQ/100 or Manipulating Strings from the TLDP Advanced Bash Scripting Guide.
Update. Here's the full command to perform the job described, and it is entirely native to the shell:
for file in */Data/Intensities/BaseCalls/*.gz; do
mv "$file" "${file%/*}/${file%%-*}_${file##*/}"
done

looping files with bash

I'm not very good in shell scripting and would like to ask you some question about looping of files big dataset: in my example I have alot of files with the common .pdb extension in the work dir. I need to loop all of them and i) to print name (w.o pdb extension) of each looped file and make some operation after this. E.g I need to make new dir for EACH file outside of the workdir with the name of each file and copy this file to that dir. Below you can see example of my code which are not worked- it's didn't show me the name of the file and didn't create folder for each of them. Please correct it and show me where I was wrong
#!/bin/bash
# set the work dir
receptors=./Receptors
for pdb in $receptors
do
filename=$(basename "$pdb")
echo "Processing of $filename file"
cd ..
mkdir ./docking_$filename
done
Many thanks for help,
Gleb
If all your files are contained within the .Repectors folder, you can loop each of them like so:
#!/bin/bash
for pdb in ./Receptors/*.pdb ; do
filename=$(basename "$pdb")
filenamenoextention=${filename/.pdb/}
mkdir "../docking_${filenamenoextention}"
done
Btw:
filenamenoextention=${filename/.pdb/}
Does a search replace in the variable $pdb. The syntax is ${myvariable/FOO/BAR}, and replaces all "FOO" substrings in $myvariable with "BAR". In your case it replaces ".pdb" with nothing, effectively removing it.
Alternatively, and safer (in case $filename contains multiple ".pdb"-substrings) is to remove the last four characters, like so: filenamenoextention=${filename:0:-4}
The syntax here is ${myvariable:s:e} where s and e correspond to numbers for the start and end index (not inclusive). It also let's you use negative numbers, which are offsets from the end. In other words: ${filename:0:-4} says: extract the substring from $filename starting from index 0, until you reach fourth-to-the-last character.
A few problems you have had with your script:
for pdb in ./Receptors loops only "./Receptors", and not each of the files within the folder.
When you change to parent directory (cd ..), you do so for the current shell session. This means that you keep going to the parent directory each time. Instead, you can specify the parent directory in the mkdir call. E.g mkdir ../thedir
You're looping over a one-item list, I think what you wanted to get is the list of the content of ./Receptors:
...
for pdb in $receptors/*
...
to list only file with .pdb extension use $receptors/*.pdb
So instead of just giving the path in for loop, give this:
for pdb in $receptors/*.pdb
To remove the extension :
set the variable ext to the extension you want to remove and using shell expansion operator "%" remove the extension from your filename eg:
ext=.pdb
filename=${filename%${ext}}
You can create the new directory without changing your current directory:
So to create a directory outside your current directory use the following command
mkdir ../docking_$filename
And to copy the file in the new directory use cp command
After correction
Your script should look like:
receptors=./Receptors
ext=.pdb
for pdb in $receptors/*.pdb
do
filename=$(basename "$pdb")
filename=${filename%${ext}}
echo "Processing of $filename file"
mkdir ../docking_$filename
cp $pdb ../docking_$filename
done

Resources