This question already has answers here:
Rename filename to another name
(3 answers)
Closed 6 years ago.
I have a bunch of directories each having multiple files.
dir1
|- part1.txt
|- part2.txt . . .
dir2
|- part1.txt
|- part2.txt . . .
I want to rename the internal files (part1.txt and so on) to something like (dir1_part1.txt). How can this be done in ubuntu?
This question explains how suffix prefix can be added or removed. But how do I add a prefix as a Directory Name?
There is a tool called perl-rename sometimes called rename, not to be confused with rename from util-linux. This tool takes a perl expression and renames accordently:
perl-rename 's~/~_~' dir1/* dir2/*
The above will rename and move all files in dir1 and dir2 to the following:
dir1/file1 -> dir1_file1
dir1/file2 -> dir1_file2
dir1/file3 -> dir1_file3
You can play with the regex online
A simple bash script using find and parameter-expansion for finding the directory name.
#!/bin/bash
find . -name "*.csv" -type f -printf '%f\n' |
while read -r x; do
mv -v "$x" "${PWD##*/}_$x"
done
To handle files with special characters:-
To handle file-names that contain newlines or other types of white space or other special characters, am adopting -print0 from find and reading them with a de-limiter '':-
Am using parameter-expansion again, to strip leading characters ./ from find command.
#!/bin/bash
find . -name "*.csv" -type f -print0 |
while IFS= read -r -d '' x; do
x="${x:2}"
mv -v "$x" "${PWD##*/}_$x"
done
A working example:-
[dude#csv_folder]$ ls *.csv
1.csv 2.csv 3.csv 4.csv
[dude#csv_folder]$ ./myScript.sh
`1.csv' -> `csv_folder_1.txt'
`2.csv' -> `csv_folder_2.txt'
`3.csv' -> `csv_folder_3.txt'
`4.csv' -> `csv_folder_4.txt'
Okay, here is a simple example.
$ mkdir dir{1..5}
$ touch dir{1..5}/part{1..5}.txt
# the command above create the files for testing
# then do the rename action
$ for f in dir*/*;do mv -v $f $(dirname $f)/$(dirname $f)_$(basename $f);done
Related
This question already has answers here:
Moving multiple files having spaces in name (Linux)
(3 answers)
Exactly how do backslashes work within backticks?
(2 answers)
Closed 2 years ago.
I have the following script that renames files based on a specific file name string. The script was working fine until I had to apply it to a directory that contains a folder name with a space.
Script:
for file in `find /home/splunkLogs/Captin/PPM\ Images/PXT -type f -name '*.jpg'`; do mv -v "$file" "${file/-0.jpg/_Page_1.jpg}"; done
You'll notice the file name "PPM Images", which has a space. I added a backslash so the path would be readable, but I get the error "mv: cannot stat /home/splunkLogs/Captin/PPM: No such file or directory. I also tried putting the folder name in quotes in the path and received the same error. Can anyone guide me with a solution for handling filename spaces with the MV command?
So do not read lines using for. Read https://mywiki.wooledge.org/BashFAQ/001 .
find /home/splunkLogs/Captin/PPM\ Images/PXT -type f -name '*.jpg' |
while IFS= read -r file; do
mv -v "$file" "${file/-0.jpg/_Page_1.jpg}"
done
or better:
find /home/splunkLogs/Captin/PPM\ Images/PXT -type f -name '*.jpg' -print0 |
while IFS= read -r -d '' file; do
mv -v "$file" "${file/-0.jpg/_Page_1.jpg}"
done
Do not use backticks `. Using $(...) instead is greatly preferred.
I am using this command and sample_numbers_names.csv file to rename multiple files in the folder which has subfolders with different file names.
while IFS=, read -a p ; do SAMPLENUM=${p[0]} ; find . -type f -name "${SAMPLENUM}*" -exec rename -v "${SAMPLENUM}" "${p[1]}_${SAMPLENUM}" {} \; ; done < sample_numbers_names.csv
The csv file has two columns first for old name and next for the new name. for e.g.
111,abc
222,xyz
After using this command the out put I am getting is like this
111.txt is converted to abc._111.txt
How to remove that dot after abc so that renamed file will look like abc_111.txt rather than abc._111.txt
The following seems to work as desired:
$ cat sample_numbers_names.csv
111,abc
222,xyz
$ mkdir -p foo/bar
$ touch foo/bar/{111,222}.txt
$ while IFS=, read old new ; do find . -type f | xargs rename "s/${old}/${new}_${old}/"; done < sample_numbers_names.csv
$ ls foo/bar/
abc_111.txt xyz_222.txt
I'm just starting to use Docker, and I'm newbie in bash scripts, but now I need to write bash script that will do next thing:
I have 2 dirs with some subdirs: Rtp/ and Rtp-[version]/, I need if Rtp-[version]/ dir exists rename it to the Rtp/ and override it's content. [version] - is dynamic number.
My dir structure:
|-- Rtp
|--- subdir 1
|--- subdir 2
|-- Rtp-1.0 (or Rtp-1.6, Rtp-2.7)
|--- subdir 1
|--- subdir 2
After this I need in the new Rtp/ dir find specific file app.properties, and change inside of it string: myvar=my value to string myvar=new value, and do the same thing with 3 more files
I tried this link: http://stackoverflow.com/questions/15290186/…: find . -name 'Rtp-' -exec bash -c 'mv $0 ${0/*/Rtp}' {} \; The problem that if dir already exists it move one directory into another.
Also I want rename it and not copy because it's big dir, and it can take some time to copy.
Thanks in advance, can you explain please the solution, in order to I will can change in the future if something will be changed.
1.
for dir in $(find Rtp-[version] -maxdepth 1 -type d): do
cp -Rf $dir Rtp
done
Find all directories in Rtp-version
Iterate through all of the results (for...)
Copy recursively to Rtp/, and -f will overwrite
2.
for f in $(find Rtp -type f -name "app.properties"): do
sed -ie s/myvar=myval/myvar=newval/ $f
done
Find all files named app.properties
Use sed (the Stream editor) to -i interactively -e search for a string (by regex) and replace it (eg s/<oldval>/<newval>/). Note that oldval and newval will need to be escaped. If they contain a lot of /'s,you could do something like s|<oldval>|<newval>|.
Based on #Brian Hazeltine answer and Check if a file exists with wildcard in shell script
I found next solution:
if ls Rtp-*/ 1> /dev/null 2>&1; then
mv -T Rtp-*/ Rtp
find appl.properties -type f -exec sed -ie 's/myvar=my value/myvar=new value/' {} \;
fi
How to change all file's extensions in a folder using one command on CLI in Linux?
Use rename:
rename 's/.old$/.new/' *.old
If you have the perl rename installed (there are different rename implementations) you can do something like this:
$ ls -1
test1.foo
test2.foo
test3.foo
$ rename 's/\.foo$/.bar/' *.foo
$ ls -1
test1.bar
test2.bar
test3.bar
You could use a for-loop on the command line:
for foo in *.old; do mv $foo `basename $foo .old`.new; done
this will take all files with extension .old and rename them to .new
This should works on current directory AND sub-directories. It will rename all .oldExtension files under directory structure with a new extension.
for f in `find . -iname '*.oldExtension' -type f -print`;do mv "$f" ${f%.oldExtension}.newExtension; done
This will work recursively, and with files containing spaces.
Be sure to replace .old and .new with the proper extensions before running.
find . -iname '*.old' -type f -exec bash -c 'mv "$0" "${0%.old}.new"' {} \;
Source : recursively add file extension to all files
(Not my answer.)
find . -type f -exec mv '{}' '{}'.jpg \;
Explanation: this recursively finds all files (-type f) starting from the current directory (.) and applies the move command (mv) to each of them. Note also the quotes around {}, so that filenames with spaces (and even newlines...) are properly handled.
I have a folder with more than 5000 images, all with JPG extension.
What i want to do, is to add recursively the "thumb_" prefix to all images.
I found a similar question: Rename Files and Directories (Add Prefix) but i only want to add the prefix to files with the JPG extension.
One of possibly solutions:
find . -name '*.jpg' -printf "'%p' '%h/thumb_%f'\n" | xargs -n2 echo mv
Principe: find all needed files, and prepare arguments for the standard mv command.
Notes:
arguments for the mv are surrounded by ' for allowing spaces in filenames.
The drawback is: this will not works with filenames what are containing ' apostrophe itself, like many mp3 files. If you need moving more strange filenames check bellow.
the above command is for dry run (only shows the mv commands with args). For real work remove the echo pretending mv.
ANY filename renaming. In the shell you need a delimiter. The problem is, than the filename (stored in a shell variable) usually can contain the delimiter itself, so:
mv $file $newfile #will fail, if the filename contains space, TAB or newline
mv "$file" "$newfile" #will fail, if the any of the filenames contains "
the correct solution are either:
prepare a filename with a proper escaping
use a scripting language what easuly understands ANY filename
Preparing the correct escaping in bash is possible with it's internal printf and %q formatting directive = print quoted. But this solution is long and boring.
IMHO, the easiest way is using perl and zero padded print0, like next.
find . -name \*.jpg -print0 | perl -MFile::Basename -0nle 'rename $_, dirname($_)."/thumb_".basename($_)'
The above using perl's power to mungle the filenames and finally renames the files.
Beware of filenames with spaces in (the for ... in ... expression trips over those), and be aware that the result of a find . ... will always start with ./ (and hence try to give you names like thumb_./file.JPG which isn't quite correct).
This is therefore not a trivial thing to get right under all circumstances. The expression I've found to work correctly (with spaces, subdirs and all that) is:
find . -iname \*.JPG -exec bash -c 'mv "$1" "`echo $1 | sed \"s/\(.*\)\//\1\/thumb/\"`"' -- '{}' \;
Even that can fall foul of certain names (with quotes in) ...
In OS X 10.8.5, find does not have the -printf option. The port that contained rename seemed to depend upon a WebkitGTK development package that was taking hours to install.
This one line, recursive file rename script worked for me:
find . -iname "*.jpg" -print | while read name; do cur_dir=$(dirname "$name"); cur_file=$(basename "$name"); mv "$name" "$cur_dir/thumb_$cur_file"; done
I was actually renaming CakePHP view files with an 'admin_' prefix, to move them all to an admin section.
You can use that same answer, just use *.jpg, instead of just *.
for file in *.JPG; do mv $file thumb_$file; done
if it's multiple directory levels under the current one:
for file in $(find . -name '*.JPG'); do mv $file $(dirname $file)/thumb_$(basename $file); done
proof:
jcomeau#intrepid:/tmp$ mkdir test test/a test/a/b test/a/b/c
jcomeau#intrepid:/tmp$ touch test/a/A.JPG test/a/b/B.JPG test/a/b/c/C.JPG
jcomeau#intrepid:/tmp$ cd test
jcomeau#intrepid:/tmp/test$ for file in $(find . -name '*.JPG'); do mv $file $(dirname $file)/thumb_$(basename $file); done
jcomeau#intrepid:/tmp/test$ find .
.
./a
./a/b
./a/b/thumb_B.JPG
./a/b/c
./a/b/c/thumb_C.JPG
./a/thumb_A.JPG
jcomeau#intrepid:/tmp/test$
Use rename for this:
rename 's/(\w{1})\.JPG$/thumb_$1\.JPG/' `find . -type f -name *.JPG`
For only jpg files in current folder
for f in `ls *.jpg` ; do mv "$f" "PRE_$f" ; done