Rename files in sub-directories using find and rename - find

i wish to rename files with single digit numbers by adding a "0" in front, while ignoring files with double digit numbers, for example: 1.fileA, 2.fileB to 01.fileA, 02.fileB, and ignoring files 10.fileK, 11.fileL
when i use the following command, nothing happens. i assume it's because find returns the full path of the filename for which my rename function does not work. below, mediaDir is the path to my folder where my media files are located.
i tried the following but it still does not work:
find "$mediaDir" -type f -name "*.mp4" -exec rename 's/^(\d)\./0$1./' {} \;
so i tried the following instead, which also does not rename the files:
find "$mediaDir" -type f -name "*.mp4" -exec rename 's/^(\d)\./0$1./' $(basename {}) \;
although the following correctly lists out the basename of the files without the fullpath
find "$mediaDir" -type f -name "*.mp4" -exec basename {} \;
i have spent a whole day googling and trying but to no avail. please help.

After struggling further to understand the find command, thanks to Kusalananda who did a great job explaining "find" that "man find" does an incomplete job of:
Basic usage of -exec
In my question above, -exec doesn't work because find returns the full path to the found file, which makes my rename's regex using ^ fail since the digit to be appended to is no more at the start of the string, being within the full path.
Using "-execdir" instead, returns only the filename minus the path; however, GNU find prefixes the returned filename with "./" which defeats my regex. the following finally worked:
find "$mediaDir" -type f -name "*.mp4" -execdir rename 's/\/(\d)\./\/0$1./' {} \;
Note that the "^" is no more in my regex expression, due to the "./" prefix that "find" appends
To use -exec instead of -execdir, the following worked:
find "$mediaDir" -type f -name "*.mp4" -exec basename {} \; -exec rename 's/\/(\d)\./\/0$1./' {} \;
It seems that "-execdir" is shorter and better than "-exec".

Use find with regex to match only one digit and then process the output in a loop, executing mv to rename the file.
while read file;
do
filename=${fil3##*/}; # Extract the directory
dir=${file%/*} # Extrasct the file name
mv "$file" "$dir/0$filename" # Execute the move command
done <<< "$(find /path/to/dir -regextype posix-extended -regex "^.*/[[:digit:]]{1}\.file.*")"

Related

Find files and delete characters in the filenames

So I have a directory called testdir and I want to delete the underscores in the filenames from the files in that directory.
I tried to use this command
find testdir -type f -exec ls {} \; | sed 's/_*//'
It will output the filenames without the underscores but it won't delete the underscores permanently. Could anyone help me?
Thanks!
If you are just looping through the files in your dir, use a simple loop:
while IFS= read -r file
do
echo mv "$file" "${file//_/}" #once you are sure it works, remove the echo!
done < <(find -type f -name "*_*")
This will feed the while loop with the output of the find command. Then, uses ${var//_/} to remove all _ in the name.
Why wasn't your approach working?
Because you are saying
find ... -exec ls {} \; | sed '...'
That is, you are finding something and then changing the output with sed. That is, nothing is done to the file itself.
This may help you
find testdir -type f | rename 's/_//'
Regards

Files not available after running find command

I tried to rename files ending with ".txt" to ".abc" using the find command as below. Now the files are not available on my disk.
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$1.abc"' {} \;
can someone explain me the above command in detail what is did with the files.
Is there any possibility to retrive those, if yes how ?
You used the wrong variable and most of the files cannot be retrieved.
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$1.abc"' {} \;
will rename every .txt file to a file called .abc. So if you files named bar.txt and foo.txt it will rename bar.txt to .abc and then rename foo.txt to .abc which will overwrite the original contents of bar.txt. You cannot see the file because it is .abc and is hidden under a normal list. If you run 'ls -a' you will see a file named ".abc" which will have the contents of the last .txt file that was renamed.
I am not sure how to do exactly what you wanted but running
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$0.abc"' {} \;
will rename each .txt file to a .txt.abc file. So you would have bar.txt.abc and foo.txt.abc
The explanation of rondo is correct.
But what are the solutions for your problem?
If you want to replace the suffix .txt with .abc you can use rename
You will have success, if you use rename and find like this:
find . -type f -iname '*.txt' -print0 | xargs -0 rename .txt .abc
For all files found by find like x.txt or a/b.txt the appropriate command will execute, e.g.
rename .txt .abc x.txt
rename .txt .abc a/b.txt
so x.txt -> x.abc, and a/b.txt -> a/b.abc
If you only want to add the suffix .abc to all files you can still use mv
find . -type f -iname '*.txt' -print0 | xargs -0 mv {} {}.abc
With xargs for each file the command mv is executed.
BTW: with the find option "-print0" and the xargs option "-0" the commands work also with filenames which includes spaces.

solaris md5 files in all subdirectories

I need to search all duplicated files in folder and subdirectories of this folder. how use find and md5 to get list for all files?
find ./ -type f -name '*' -exec md5sum {} > checksums.txt \;
above comand doesnt work
or is it possible to remove the 'newer one'?
thx in advance
You overwrite the checksums.txt during the find with each file found.
The -name '*'does not add anything to the query, so you could enter
find . -type f -exec md5sum {} \; > checksums.txt
Or use append (>>).

Solaris: Find files matching a pattern but only display the directory name

Like it says above. I'm trying to find a simple way to look for a pattern in a file name and display only the directory in which it is found.
For example, given a tree structure that looks like this:
./projecta
./projecta/src/code1.p
./projecta/src/code2.p
./projecta/util.p
./projectb
I would want the command "whatever *.p" to return:
./projecta/src
./projecta
Hope that makes sense. Any further info, please signify in the usual manner.
TIA
N/
To display the directories of .c files:
find . -name \*.c -exec dirname {} \; | uniq
To display the directories of .html files:
find . -name \*.html -exec dirname {} \; | uniq
If you want to use that in a script,
#/bin/bash
ext=$1
find . -name \*.${ext} -exec dirname {} \; | uniq

xargs: unterminated string error - How to go around files with illegal characters?

I'm writing a one-liner to go through all sub-folders under my current folder "A", get the list of files then search for those files in my other folder "B". If the file is found then this file is deleted from "A". All works well until I hit those files with illegal characters. The command quits with xargs: unterminated string.
ls -R * | xargs -I{} find /my/otherfolder/B -type f -name {} -exec rm -f {} \;
I tried putting quotes here and there - no luck. Does anyone know how to get around this one??
Got the same error, but slightly different command.
For me it worked something like that:
find . -type f -name "*php" -print0| xargs -0 grep -sli stringtofind
It didn't work until I used -print0 and -0 options.
Hope that helps.