Is there any way of batch renaming files in sub directories?
For example:
Rename *.html to *.htm in a folder which has directories and sub directories.
Windows command prompt: (If inside a batch file, change %x to %%x)
for /r %x in (*.html) do ren "%x" *.htm
This also works for renaming the middle of the files
for /r %x in (website*.html) do ren "%x" site*.htm
find . -regex ".*html$" | while read line;
do
A=`basename ${line} | sed 's/html$/htm/g'`;
B=`dirname ${line}`;
mv ${line} "${B}/${A}";
done
In python
import os
target_dir = "."
for path, dirs, files in os.walk(target_dir):
for file in files:
filename, ext = os.path.splitext(file)
new_file = filename + ".htm"
if ext == '.html':
old_filepath = os.path.join(path, file)
new_filepath = os.path.join(path, new_file)
os.rename(old_filepath, new_filepath)
If you have forfiles (it comes with Windows XP and 2003 and newer stuff I think) you can run:
forfiles /S /M *.HTM /C "cmd /c ren #file *.HTML"
In Bash, you could do the following:
for x in $(find . -name \*.html); do
mv $x $(echo "$x" | sed 's/\.html$/.htm/')
done
In bash use command rename :)
rename 's/\.htm$/.html/' *.htm
# or
find . -name '*.txt' -print0 | xargs -0 rename 's/.txt$/.xml/'
#Obs1: Above I use regex \. --> literal '.' and $ --> end of line
#Obs2: Use find -maxdepht 'value' for determine how recursive is
#Obs3: Use -print0 to avoid 'names spaces asdfa' crash!
I'm sure there's a more elegant way, but here's the first thing that popped in my head:
for f in $(find . -type f -name '*.html'); do
mv $f $(echo "$f" | sed 's/html$/htm/')
done
On Linux, you may use the 'rename' command to rename files in batch.
AWK on Linux. For the first directory this is your answer... Extrapolate by recursively calling awk on dir_path perhaps by writing another awk which writes this exact awk below... and so on.
ls dir_path/. | awk -F"." '{print "mv file_name/"$0" dir_path/"$1".new_extension"}' |csh
On Unix, you can use rnm:
rnm -rs '/\.html$/.htm/' -fo -dp -1 *
Or
rnm -ns '/n/.htm' -ss '\.html$' -fo -dp -1 *
Explanation:
-ns : name string (new name). /n/ is a name string rule that expands to the filename without the extension.
-ss : search string (regex). Searches for files with match.
-rs : replace string of the form /search_regex/replace_part/modifier
-fo : file only mode
-dp : depth of directory (-1 means unlimited).
there is pretty powerfull forfiles command:
forfiles /? gives u hint of what is possible with the command.
in this case it can be used like:
forfiles /S /M *.html /C "cmd /c rename #file #fname.htm"
Related
I have a dictionary.txt which i will be using to search some files using find command.
example of dictionary.txt:
*.xlsx
*project*
I am trying to make this command works but no luck
cat dictionary.txt | xargs -i find /d -iname '"{}"'
You have used single quotes in the wrong way.
Change your command in cat dictionary.txt | xargs -i find /d -iname "{}"
I have a bunch of files in a folder. Some of them are of the format:
IMG_YYYYMMDD_junk.ext
I would like to rename such files into
YYYY-MM-DD junk.ext
Example: IMG_20170214_3939233.jpg becomes 2017-02-14 3939233.jpg
So far I was successful in filtering files I need:
find *.jpg *.jpeg *.png | egrep '^IMG_[0-9]{1,8}'
and I know I need to use sed but I am getting no where specifying and referencing match-groups in my regex for further filename transformation. I know I may have to use xarg later on in the pipe but so far I wasn't successful in transforming each file name just to print it out.
Perhaps, sed is not the best option here.
With Perl‘s standalone rename command and bash‘s option nullglob:
shopt -s nullglob
rename -n 's/.*_(....)(..)(..)_([0-9]+.*)/$1-$2-$3 $4/' *.jpg *.jpeg *.png
If everything looks fine remove option -n.
A logic in bash with NO external tools!
You can run the below script from inside the folder containing these images.
#!/bin/bash
for file in *.{jpg,jpeg,png}; do
IFS="_" read -ra fileNameList <<<"$file"
year="${fileNameList[1]:0:4}"
month="${fileNameList[1]:4:2}"
day="${fileNameList[1]:6:2}"
targetFileName="${year}-${month}-${day} ${fileNameList[2]}"
# Remove this line and uncomment the line with 'mv' if things look OK
echo "$file" "$targetFileName"
#mv -v "$file" "$targetFileName"
done
The idea is tot split the file name on _ and store them in array. Then parse the individual digits from the number and form the final name from the combined elements.
With GNU Parallel it looks like this:
find *.jpg *.jpeg *.png |
parallel mv {} '{= s/IMG_(....)(..)(..)_/$1-$2-$3 / =}'
Or:
parallel mv {} '{= s/IMG_(....)(..)(..)_/$1-$2-$3 / =}' ::: *.jpg *.jpeg *.png
I assume you're not really interested in the find command, but in nailing down the sed regex:
find ~ -type f -maxdepth 1 -name IMG*.jpg | sed -e 's/\(IMG_\)\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)_/\2-\3-\4 /g'
Your example:
echo "IMG_20170214_3939233.jpg" | sed -e 's/\(IMG_\)\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)_/\2-\3-\4 /g'
output:
2017-02-14 3939233.jpg
A mostly-bash solution using its regex-matching operator, =~, which supports capture groups that can be accessed via the built-in "${BASH_REMATCH[#]}" array variable:
for file in *; do
[[ $file =~ ^IMG_([0-9]{4})([0-9]{2})([0-9]{2})_(.+\.(jpg|jpeg|png))$ ]] || continue
mv "$file" "${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]} ${BASH_REMATCH[4]}"
done
I have a text file that contains a list of files like this:
Contents of list.txt:
file1.txt
file2.txt
file3.txt
I need to search through a directory (and it's subdirectories) to find each file and copy it into another directory.
Current directory:
-dir
-subdir1
-subdir2
-subdir3
-subdir4
-outputdir
In this example, I might:
find file1.txt in subdir3
find file2.txt in subdir1
file3.txt might not exist
In this case, it would copy file1.txt & file2.txt into outputdir
I don't have much experience will doing this on the command line, but have 1200 files to move, so I can't do it manually. This is the closest thing I've gotten to the right thing, but it doesn't find any of the files because they are all in subdirectories:
xargs -a list.txt cp -t outputdir
An explanation of the command you give would also be immensely helpful. Searches around have also brought up "bash for loops", which I tried to use but couldn't figure out all the intricacies:
FOR /R "%~dp0" %%I IN (.) DO for /f "usebackq delims=" %%a in ("%~dp0list.txt") do echo d |xcopy "%%I\%%a" "outputdir" /e /i
If you have bash 4, use the following:
shopt -s globstar nullglob
while IFS= read -r fname; do
files=("$dir"/**/"$fname")
if (( ${#files[#]} > 0 )); then
cp "${files[#]}" "$outputdir"
fi
done < list.txt
The while loop reads from list.txt one line at a time. The ** pattern matches zero or more directories; files could contain 0 or more matching files. If the array is not empty, all file names are passed to cp for copying.
For older versions, use find:
while IFS= read -r fname; do
find "$dir" -name "$fname" -type f -exec cp {} "$outputdir" \;
done < list.txt
This simply locates all matching files under $dir and runs cp on each.
I have a directory containing hundreds of files (each having several chars). I want to join them into a single file with a separator, "|".
I tried
find . -type f | (while read line; do; cat $line; echo "|"; done;) > output.txt
But that created an infinite loop.
You can exclude output.txt from the output of find using -not -name output.txt (or as you already pointed out in the comments below, simply place the output file outside the target directory).
For example:
find . -type f -not -name output.txt -exec cat {} \; -exec echo "|" \; > output.txt
I've also taken the liberty to replace your while/cat/echo with a couple of -exec params so we can do the whole thing using a single find call.
*To answer the title of the question, since it's the first in google results (the output.txt problem is actually unrelated):
This is what I use to join .jar files to run Java app with files in lib/:
EntityManagerStoreImpl
ondra#lenovo:~/work/TOOLS/JawaBot/core$ ls
catalog.xml nbactions.xml nb-configuration.xml pom.xml prepare.sh resources run.sh sql src target workdir
ondra#lenovo:~/work/TOOLS/JawaBot/core$ echo `ls -1` | sed 's/\W/:/g'
catalog:xml:nbactions:xml:nb:configuration:xml:pom:xml:prepare:sh:resources:run:sh:sql:src:target:workdir
The file listing may be of course replaced with find ... or anything.
The echo is there to replace newlines with spaces.
Final form:
java -cp $(echo `ls -1 *.jar` | sed 's/\W/:/g') com.foo.Bar
I reused Ondra's answer, but with absolute path instead.
Command :
echo $( \find '/home/user/[path-to-webapp]/WEB-INF/lib' -name '*.jar' -print0) | \
sed 's#\.jar/#.jar:#g'
Note: I use # as sed's separator to not match the last jar in the list.
Results:
/home/user/[path-to-webapp]/WEB-INF/lib/jar1.jar:home/user/[path-to-webapp]/WEB-INF/lib/jar2.jar[...
and so
on...]:/home/user/[path-to-webapp]/WEB-INF/lib/last-jar.jar
Then, I can use this output in a javac -classpath command.
I need to convert about 12000 TIF files in many directories, and try to write bash-script:
#!/bin/bash
find -name "*.tif" | while read f
do
convert "$f" "${f%.*}.png"
rm -f "$f"
done
Why it say: x.sh: 6: Syntax error: end of file unexpected (expecting "do") and what I should to do?
Great thanks to you all, men, but I was cheated: the computer on which this should be run out works under Windows. I don't know how to work with strings and cycles in DOS, now my script look like:
FOR /R %i IN (*.tif) DO # (set x=%i:tif%png) & (gm convert %i %xtif) & (erase /q /f %i)
%i - one of the .tif files.
%x - filename with .png extension
gm convert - graphics magick utility, work similarly with image magick's convert on linux.
The syntax looks okay, but if it's a problem with EOLs, try adding a semicolon before the do to fix the syntax error (or check the newlines are actually present/encoded as ghostdog74 suggests):
find -name "*.tif" | while read f ; do # ...
Note that the find/read pattern isn't robust. Use can use find's exec capability directly (thanks Philipp for the inline command):
find -name "*.tif" -exec sh -c 'file=$0 && convert "$file" "${file%.tif}.png"' '{}' ';' -delete