Bash. Using find and a for loop. Can't find how to mv file into the directory that was found. Just moves to root directory given. - bash

Current code.
Right now I have a test format set up. Here is what I have.
files=`find C:/PATH/TO/DIRECTORY/2014-05-08 -name *.txt`
(I will be running this from C:/PATH/TO/DIRECTORY. Just right now I'm only testing on todays directory so I don't change everything in /DIRECTORY.) The .sh script is being run from /DIRECTORY therefore it is it's root.) In the implemented version find will look like this:
files=`find C:/PATH/TO/DIRECTORY -name *.txt`
for file in $files; do
#code to manipulate filename
mv $file $newFilename
The problem that I am getting is that this renames the old file name into the new file name, but the new files are in /DIRECTORY when I want them to be in the directory that the program is currently looping through. Which in this case is /DIRECTORY/2014-05-08.
I was just going to make a variable for the current directory of $file, but couldn't figure out how and use:
mv $file /CWD/$newFilename
but I was unable to find a way to assign CWD the directory that $file was in. This would probably be the easiest way if it's possible.

This would be a better way to code that:
find dir -name \*.txt |
while IFS= read -r file; do
dir=$(dirname "$file")
file=$(basename "$file")
newfile=...whatever...
mv "$dir/$file" "$dir/$newfile"
done
Using a for loop over the results of find will iterate over the words in the result, not necessarily the lines -- if there's a filename with a space in it, the for loop won't get the right filename.
The while IFS= read -r line technique I demonstrate is the safest way to iterate over the lines of the result of a command.
There are other issues in my code that I don't think are strictly relevant here.

Related

script read file contents and copy files

I wrote a script in bash that should read the contents of a text file, look for the corresponding files for each line, and copy them to another folder. It's not copying all the files, only two, the third and the last.
#!/bin/bash
filelist=~/Desktop/file.txt
sourcedir=~/ownCloud2
destdir=~/Desktop/file_out
while read line; do
find $sourcedir -name $line -exec cp '{}' $destdir/$line \;
echo find $sourcedir -name $line
sleep 1
done < "$filelist"
If I use this string on the command line it finds me and copies the file.
find ~/ownCloud2 -name 123456AA.pdf -exec cp '{}' ~/Desktop/file_out/123456AA.pdf \;
If I use the script instead it doesn't work.
I used your exact script and had no problems, for both bash or sh, so maybe you are using another shell in your shebang line.
Use find only when you need to find the file "somewhere" in multiple directories under the search start point.
If you know the exact directory in which the file is located, there is no need to use find. Just use the simple copy command.
Also, if you use "cp -v ..." instead of the "echo", you might see what the command is actually doing, from which you might spot what is wrong.

Unable to rename and move files from one location to another

I need to add prefix C_ and then move files from tmp location to target location.
Here is the script
I am not allowed to place script in current directory.
for tmpfile in /home/asmita/tmp
do
mv "$tmpfile" "C_${tmpfile}"
mv "C_${tmpfile}" /home/tgasmita
done
When I try moving prefixed files I get error C_/home/asmita/tmp/xyz.txt not found. as entire path is stored in tmpfile variable.
Change your code to use the basename and the dirname command to get the filename and the directory name. Use these to combine the values and get the new path.
for tmpfile in /home/asmita/tmp
do
DIRPATH=$(dirname "${tmpfile}")
FILENAME=$(basename "${tmpfile}")
mv "$tmpfile" "${DIRPATH}C_${FILENAME}"
mv "${DIRPATH}C_${FILENAME}" /home/tgasmita
done
There are many ways to do this. First let me fix your script.
1.In below code make sure that you are passing only filename not the full path. Below script is valid only if know the FILENAME
#!/bin/sh
for tmpfile in /home/asmita/tmp
do
mv "{tmpfile}/filename.txt" "/home/tgasmita/C_filename.txt"
done
2.If you do not know file name and you want to rename and move .txt files to another folder then you might like below script.
#!/bin/sh
lines=`find /home/asmita/tmp -name "*.txt" -printf "%f\n";`
for i in ${lines[#]}
do
mv "/home/asmita/tmp/${i}" "/home/tgasmita/C_${i}"
done
Please note that I m looking for only text file in source folder(/home/asmita/tmp
) You can change .txt to other extension according to requirement. If you want to move and rename all files from source folder then just replace "*.txt" to ".*" from second line.

batch renaming of multiple files of same extension

I need to rename multiple files without knowing the filename(basename/string name ) of the file.
i tried with:
for i in $(ls /Users/Destiny/Desktop/Index/*.ebwt);
do
mv -v "$i" "${i/hsa/hsa.genome.V86C}"; ## works when i know the string to replace
done
but what if dont know the filename(string name)?
Before rename: hsa.1.ebwt hsa.2.ebwt hsa.3.ebwt hsa.4.ebwt
After rename: hsa.genome.V86C.1.ebwt hsa.genome.V86C.2.ebwt hsa.genome.V86C.3.ebwt hsa.genome.V86C.4.ebwt
You could do something with a find in your directory. And if they all have the same extension then it could be something like below with your move that you currently have:
find /Users/Destiny/Desktop/Index -type f -name "*.ebwt" | while read file;
do
mv -v "$file" "${file/hsa/hsa.genome.V86C}";
done
This will rename it inside of the current directory, and if you want to move it to a different directory later down the line, you could surround second argument like this with basename to make moving easier:
"/SomeDirectory/$(basename ${file/hsa/hsa.genome.V86C})"
You could also put a -maxdepth 1 after the directory you want to find if you dont want it to be recursive in the find

Rename files within folders to folder names while retaining extensions

I have a large repository of media files that follow torrent naming conventions- something unpleasant to read. At one point, I had properly named the folders that contain said files, but not want to dump all the .avi, .mkv, etc files into my main media directory using a bash script.
Overview:
Current directory tree:
Proper Movie Title/
->Proper.Movie.Title.2013.avi
->Proper.Movie.Title.2013.srt
Title 2/
->Title2[proper].mkv
Movie- Epilogue/
->MOVIE EPILOGUE .AVI
Media Movie/
->MEDIAMOVIE.CD1.mkv
->MEDIAMOVIE.CD2.mkv
.
.
.
Desired directory tree:
Proper Movie Title/
->Proper Movie Title.avi
->Proper Movie Title.srt
Title 2.mkv
Movie- Epilogue.avi
Media Movie/
->Media Movie.cd1.mkv
->Media Movie.cd2.mkv
Though this would be an ideal, my main wish is for the directories with only a single movie file within to have that file be renamed and moved into the parent directory.
My current approach is to use a double for loop in a .sh file, but I'm currently having a hard time keeping new bash knowledge in my head.
Help would be appreciated.
My current code (Just to get access to the internal movie files):
#!/bin/bash
FILES=./*
for f in $FILES
do
if [[ -d $f ]]; then
INFILES=$f/*
for file in $INFILES
do
echo "Processing >$file< folder..."
done
#cat $f
fi
done
Here's something simple:
find * -type f -maxdepth 1 | while read file
do
dirname="$(dirname "$file")"
new_name="${dirname##*/}"
file_ext=${file##*.}
if [ -n "$file_ext" -a -n "$dirname" -a -n "$new_name" ]
then
echo "mv '$file' '$dirname/$new_name.$file_ext'"
fi
done
The find * says to run find on all items in the current directory. The -type f says you only are interested in files, and -maxdepth 1 limits the depth of the search to the immediate directory.
The ${file##*.} is using a pattern match. The ## says the largest left hand match to *. which is basically pulling everything off to the file extension.
The file_dir="$(dirname "$file")" gets the directory name.
Note quotes everywhere! You have to be careful about white spaces.
By the way, I echo instead of doing the actual move. I can pipe the output to a file, examine that file and make sure everything looks okay, then run that file as a shell script.

Find/Match variable filenames and move files to respective directory

I've never come to SO asking "Do my homework" but I really don't know where to start with this one.
I have a load of documents which are dumped in a directory after being auto-signed using JSignPdf (--output-directory option seemingly has no ability to output to same as input):
/some/dir/Signed/PDF1_signed.pdf
/some/dir/Signed/PDF2_signed.pdf
/some/dir/Signed/PDF2_signed.pdf
I'd like to then find their source/unsigned counterparts:
/some/dir/with/docs/PDF1.pdf
/some/dir/where/is/PDF2.pdf
/some/dir/why/this/PDF3.pdf
...and move the signed PDFs into the respective directories.
I use the command, to find all the PDFs in the variety of directories:
find . -name '*.pdf' -exec sh -c 'exec java -jar jsignpdf-1.4.3/JSignPdf.jar ... ' sh {} +
...and I've tried things like making find output a variable and then using IF THEN to match with no success. Would I need find output to be made into multiple variables? I'm so lost :(
I'd like to accomplish this in some shell, but if there are Perl junkies out there or anything else, I am more than happy for another portable solution.
I've tried to break it down, but still don't understand how to accomplish it...
find files matching VarName without _signed
move _signed file with matching name to the directory of found file
Thanks for any help/guidance.
Use a while loop to read each file found by find and move it to the correct place:
find /some/dir -name "*.pdf" ! -name "*_signed.pdf" -print0 | while IFS= read -d '' -r file
do
f="${file##*/}"
mv "/some/dir/Signed/${f%.*}_signed.pdf" "${file%/*}"
done
I have a similar problem I've been working on. Since the path manipulation required to convert /some/dir/where/is/PDF2.pdf to /some/dir/Signed/PDF2_signed.pdf is fairly simple but more involved than can be done in a simple one-liner, I've been using find to locate the first set, and using a simple loop to process them one at a time. You did mention homework, so I'll try not to give you too much code.
find /dir/containing/unsigned -name '*.pdf' -print0 | while IFS= read -d path; do
fetch_signed_version "$path"
done
where fetch_signed_version is a shell function you write that, given a path such as /some/dir/where/is/PDF2.pdf, extracts the directory (/some/dir/where/is), computes the signed PDF's name (PDF2_signed.pdf), then executes the necessary move (mv /some/dir/Signed/$signed_pdf /some/dir/where/is)
fetch_signed_version is actually pretty simple:
fetch_signed_version () {
dir=${1%/*}
fname=${1##*/}
signed_name=${fname%.pdf}_signed.pdf
mv "/some/dir/Signed/$signed_name" "$dir"
}

Resources