Bash - Moving files from subdirectories - bash

I am relatively new to bash scripting.
I need to create a script that will loop through a series of directories, go into subdirectories with a certain name, and then move their file contents into a common folder for all of the files.
My code so far is this:
#!/bin/bash
#used to gather usable pdb files
mkdir -p usable_pdbFiles
#loop through directories in "pdb" folder
for pdbDirectory in */
do
#go into usable_* directory
for innerDirectory in usable_*/
do
if [ -d "$innerDirectory" ] ; then
for file in *.ent
do
mv $file ../../usable_pdbFiles
done < $file
fi
done < $innerDirectory
done
exit 0
Currently I get
usable_Gather.sh: line 7: $innerDirectory: ambiguous redirect
when I try and run the script.
Any help would be appreciated!

The redirections < $innerDirectory and < $file are invalid and this is causing the problem. You don't need to use a loop for this, you can instead rely on the shell's filename expansion and use mv directly:
mkdir -p usable_pdbFiles
mv */usable_*/*.ent usable_pdbFiles
Bear in mind that this solution, and the loop based one that you are working on, will overwrite files with the same name in the destination directory.

Related

unix shell scripting- Using mv command in if condition

I want to move a file to a folder based on its file extension.
example: if the file is .csv,it should move to COMPLETED folder , if the file has any extension other any .csv then it should move to REGULAR folder.
Below is my shell script and its not working. Can you let me know what is the problem with it?
#!/bin/bash
cd /apps/int/apd/$1/work
if ls /apps/int/apd/$1/work/*.csv &> /dev/null; then
mv *.csv /apps/int/apd/$1/COMPLETED
else
/apps/int/apd/$1/Regular
fi
Why do you have to check the existence of *.csv files?
#!/bin/bash
cd /apps/int/apd/$1/work
mv *.csv /apps/int/apd/$1/COMPLETED 2>/dev/null
mv * /apps/int/apd/$1/Regular
Here first .csv files are moved to COMPLETED folder. Then rest of the files are moved to Regular folder.
I am assuming you have created COMPLETED and Regular folders.
Change YOUR_PATH with your specific path and your path for /COMPLETED/ and /REGULAR/.
If I got what you wanted to explain i think your variables look like theese:
/YOUR_PATH/ = /apps/int/apd/$1/work
/COMPLETED/ = /apps/int/apd/$1/COMPLETED
/REGULAR/ = /apps/int/apd/$1/Regular
You can try this. :)
#!/bin/bash
for filename in /YOUR_PATH/*;
do
Path="$filename"
extension="${filename##*.}"
if [ "${extension}" = 'csv' ]; then
mv $Path /COMPLETED/
else
mv $Path /REGULAR/
fi
done
If you need anything pls leave a comment. :)

Bash If then that reads a list in a file condition

Here is the condition:
I have a file with all packages installed.
I have a folder with all kinds of other packages, but they include all of the ones in the list, plus more.
I need a bash script that will read the file and check a folder for packages that don't exist in the list then remove them, they are not needed, but keep the packages that are on the list in that folder.
Or perhaps the bash should read folder then if packages in the folder aren't on the list them rm -f that or those packages.
I am familiar with writing if then conditional statements, I just don't know how to do if making the items in the list a variable or variables (in a loop).
thanks!
I would move the packages on the list to a new folder, delete the original folder, and move the temporary folder back:
DIR=directory-name
mkdir "$DIR-tmp"
while read pkgname; do
if [[ -f "$DIR/$pkgname" ]]; then
mv "$DIR/$pkgname" "$DIR-tmp"
fi
done < package-list.txt
# Confirm $DIR-tmp has the files you want first!
rm -rf "$DIR"
mv "$DIR-tmp" "$DIR"
I think you want something like this:
for file in $(ls folder) ; do
grep -E "$file" install-list-file >/dev/null || \
echo $file
done > rm-list
vi rm-list # view file to ensure correct
rm $(<rm_list)
There are ways to make this faster (using parameter substitution to avoid fork/exec's), but I recommend avoiding fancy shell stuff [${file##*/}] until you've got the basics down. Also, this script basically translates the description into a script and is not intended to be much more than a guide on how to approach the problem.

Bash, Move file help in variable

for i in *.txt
do
#Text files
echo $i
#checking for existing files
if [ -f ~/txt/$i ]
then
j=1
#Stripping .txt from the files
temp=${i%".txt"}
#appending filaname with counter "($j)"
i=$temp\($j\).txt
#move to folder /txt
mv $i ~/txt
else
mv $i ~/txt
fi
done
My loop checks a folder for an existing file, if that file name exists, the file name is appended (ex (1), (2) etc.
Once the file name has been renamed and it is held in $i I try to mv it but I'm getting:
mv: cannot stat 'list(1).txt': No such file or directory
I tried mv {$i} ~/txt, mv [$i] ~/txt etc...no luck. Any ideas?
You are overwriting the actually name of the file here:
i=$temp\($j\).txt
Instead, use a new variable for the new name. Something like this.
newname=$tmp\($j\).txt
#move to folder /txt
mv $i ~/txt/$newname
You say:
Once the file has been renamed and it is held in $i...
But that is wrong - the file has not been renamed at this point.
You manipulated some text in a variable. That does not have any effect on the filesystem until you run a command, such as through using mv.
Also, in your else statement, it is not clear to me why you are running mv on a file that does not exist (fails the -f test).
I had some code here, but from reading your program again, I'm not sure exactly what you're trying to accomplish, exactly...

Simple Bash Script File Copy

I am having trouble with a simple grading script I am writing. I have a directory called HW5 containing a folder for each student in the class. From my current directory, which contains the HW5 folder, I would like to copy all files starting with the word mondial, to each of the students' folders. My script runs but does not copy any of the files over. Any suggestions?
#!/bin/bash
for file in ./HW5; do
if [ -d $file ]; then
cp ./mondial.* ./$file;
fi
done
Thanks,
The first loop was executing only once, with file equal ./HW5. Add the star to actually select the files or directories inside it.
#!/bin/bash
for file in ./HW5/*; do
if [ -d "$file" ]; then
cp ./mondial.* ./"$file"
fi
done
As suggested by Mark Reed, this can be simplified:
for file in ./HW5/*/; do
cp ./mondial.* ./"$file"
done

shell create new folder

I have many files' path, but I need to copy all files into other location /sample, and I want to copy files into different folders:
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59329/111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_1.fq.gz
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59329/111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_2.fq.gz
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59329/clean_111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_1.fq.gz.total.info
I want to copy those files into AS34_59329 folder inside /sample
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59328/111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_1.fq.gz
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59328/111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_2.fq.gz
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59328/clean_111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_1.fq.gz.total.info
I want to copy those file into AS34_59328 folder inside /sample
I write codes to scp all file into /sample folder, but I don't know how to put each files into different sub-directory, like:
/ifshk5/BC_IP/PROJECT/T11073/T11073_RICekkR/Fq/AS34_59328/clean_111220_I631_FCC0E5EACXX_L4_RICwdsRSYHSD11-2-IPAAPEK-93_1.fq.gz.total.info
put into AS34_59328
#! /bin/bash
while read myline
do
for i in $myline
do
if [ -f $i]; then
#how to put different files into different sub-directory
scp -r $i xxx#191.168.174.43:/sample
fi
done
done < data.list
new changed part
#! /bin/bash
while read myline
do
for i in $myline
do
if [ -f $i ]
then
relname=$(echo $i | sed 's%\(/[^/][^/]*\)\{5\}/%%')
echo $relname
fi
done
done < /home/jesse/T11073_all_3254.fq.list
It appears you need to strip the leading 5 components of the pathname off the filename. Since you don't have spaces in your names (the way you're using for i in $myline precludes that possibility), you can use:
#! /bin/bash
while read myline
do
for i in $myline
do
if [ -f $i ]
then
relname=$(echo $i | sed 's%\(/[^/][^/]*\)\{5\}/%%')
scp -r $i xxx#191.168.174.43:/sample/$relname
fi
done
done < data.list
The regex is just a way of looking for a sequence of five sets of slash followed by one or more non-slashes plus one more slash and deleting them. Since slashes figure prominently in the search, I used % to mark the sections of the s/// operation instead.
For example, given the input:
/a/b/c/d/e/f/g
the output from the sed is:
f/g
Note that this code does not explicitly create directories on the remote machine; it just specifies where the file is to go. If you need to create them too, you will have to investigate ssh, probably, to run mkdir -p /sample/$(dirname $relname) on the remote machine (where the dirname operation can be run either locally or remotely).
Note that scp has a recursive copy mode (-r) which would simplify things considerably if you knew you needed to copy all the files from the local directory to the remote.

Resources