batch renaming of multiple files of same extension - bash

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

Related

Renaming multiple files in a nested structure

I have a directory with this structure:
root
|-dir1
| |-pred_20181231.csv
|
|-dir2
| |-pred_20181234.csv
...
|-dir84
|-pred_2018123256.csv
I want to run a command that will rename all the pred_XXX.csv files to pred.csv.
How can I easily achieve that?
I have looked into the rename facility but I do not understand the perl expression syntax.
EDIT: I tried with this code: rename -n 's/\training_*.csv$/\training_history.csv/' *.csv but it did not work
Try with this command:
find root -type f -name "*.csv" -exec perl-rename 's/_\d+(\.csv)/$1/g' '{}' \;
Options used:
-type f to specify file or directory.
-name "*.csv" to only match files with extension csv
-exec\-execdir to execute a command, in this case, perl-rename
's/_\d+(\.csv)/$1/g' search a string like _20181234.csv and replace it with .csv, $1 means first group found.
NOTE
Depending in your S.O. you could use just rename instead of perl-rename.
Use some shell looping:
for file in **/*.csv
do
echo mv "$(dirname "$file")/$(basename "$file")" "$(dirname "$file")/pred.csv"
done
On modern shells ** is a wildcard that matches multiple directories in a hierarchy, an alternative to find, which is a fine solution too. I'm not sure if this should instead be /**/*.csv or /root/**/*.csv based on tree you provided, so I've put echo before the 'mv' to see what it's about to do. After making sure this is going to do what you expect it to do, remove the echo.

Can't rename, No such file or directory

I have a root folder (03_COMPLETE), inside which are 40 subfolders two levels down (all called CHILD_PNG) that contain .png files I want to rename. There are 6 complete folders I have to go through, with tens of thousands of files. All files are currently named like this: 123456_lifestyle.png, I want them named to lifestyle_123456.png.
My code:
find . -mindepth 2 -type f -iname '*.png' -print0 | xargs -0 /usr/local/bin/rename -v 's/\/([0-9]+)_([A-Za-z]+[0-9])/\/$2_$1/'\;
If I run this on an individual folder of .png files (without using -mindepth) it renames them. However if I run it on the root 03_COMPLETE directory to try and do all the renaming at once, I get lines of errors like this:
Can't rename
'/Volumes/COMMON-LIC-PHOTO/RETOUCHING/04_DELIVERY_PNG/Computer1/03_COMPLETE/06052017_NYS5_W_1263_Output/CHILD_PNG/123456_lifestyle.png'
to
'/Volumes/COMMON-LIC-PHOTO/RETOUCHING/04_DELIVERY_PNG/Computer1/03_COMPLETE/NYS5_06052017_W_1263_Output/CHILD_PNG/123456_lifestyle.png':
No such file or directory
I think it might have something to do with the names of the folder 1 level down (eg. here NYS5_06052017_W_1263_Output) because it did rename on a couple of folders named Bustform_000. Most of the folders though start with a number like 06052017.
I can't figure out why this will work at the .png folder level but won't work on the root folder, and why it will rename in a few folders but most of them it won't.
Also what is weird is that in the error it says it is trying to rename 123456_lifestyle.png to the same filename. Why would it do that? Any ideas?
This might help:
find 03_COMPLETE -type f | xargs -n 1 rename -n 's|/([^_/]*)_([^_/]*).png$|/$2_$1.png|'
Remove -n if output is okay.
You could change directory into each of the CHILD_PNG directories and run a single rename in there on all the files so you don't exec a new rename for every single file:
find 03_COMPLETE -type d -name CHILD_PNG -execdir bash -c "cd {}; rename -n '...' *.png" \;
The issue with your original Regex is, it matches the directory names of the form "xxxxx_yyyyy" and tries to convert them into "yyyyy_xxxxx", which, of course, doesn't exist. Since you're interested in changing only the filenames, and all of them end with .png, you can use the below Regex. Additionally, as you're trying to match a literal '/', you can choose a different character like '|' as delimiter to make the Regex easier to read
's|/([0-9]+)_([A-Za-z]+[0-9]*)(\.[Pp][Nn][Gg])|/$2_$1$3|'

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.

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.

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.

Automatically move folders based on file name?

I have about 1500 folders that I need to organize automatically via command line.
I'm looking for a way to search for all folders that contain /lib/file.php - if file.php does exist in the lib folder, I need the root folder (one level above lib) move into a new directory.
I know how to search for all folders containing /lib/file.php but can't figure out how to move them automatically into a new folder. For example, if /test123/lib/file.php exists, then the test123 folder should be moved into a new folder...
Try using pipe chain of find, sed, xargs and mv
find -type f -wholename '*/lib/file.php' | sed 's:/lib/file\.php$::' | xargs -I dirs mv dirs /path/to/new/dir/
Something like this, maybe:
for d in *
do
if [[ -r "${d}/lib/file.php" ]]
then
mv "${d}" "/some/new/place/."
fi
done

Resources