How to rename multiple files at once - linux

I have lots of files, directories and sub-directories at my file system.
For example:
/path/to/file/test-poster.jpg
/anotherpath/my-poster.jpg
/tuxisthebest/ohyes/path/exm/bold-poster.jpg
I want to switch all file names from *-poster.jpg to folder.jpg
I have tried with sed and awk with no success.
little help?

You can do it with find:
find -name "*poster.jpg" -exec sh -c 'mv "$0" "${0%/*}/folder.jpg"' '{}' \;
Explanation
Here, for each filename matched, executes:
sh -c 'mv "$0" "${0%/*}/folder.jpg"' '{}'
Where '{}' is the filename passed as an argument to the command_string:
mv "$0" "${0%/*}/folder.jpg"
So, at the end, $0 will have the filename.
Finally, ${0%/*}/folder.jpg expands to the path of the old filename and adds /folder.jpg.
Example
Notice I'm replacing mv with echo
$ find -name "*poster.jpg" -exec sh -c 'echo "$0" "${0%/*}/folder.jpg"' '{}' \;
./anotherpath/my-poster.jpg ./anotherpath/folder.jpg
./path/to/file/test-poster.jpg ./path/to/file/folder.jpg
./tuxisthebest/ohyes/path/exm/bold-poster.jpg ./tuxisthebest/ohyes/path/exm/folder.jpg

Try this script, it should rename all the files as required.
for i in $(find . -name "*-poster.jpg") ; do folder=`echo $i | awk -F"-poster.jpg" {'print $1'}`; mv -iv $i $folder.folder.jpg; done
You can replace . to the directory where these files are placed in the command find . -name "*-poster.jpg" in the script. Let me know if it is working fine for you.

you can try it like
find -name '*poster*' -type f -exec sh -c 'mv "{}" "$(dirname "{}")"/folder.jpg' \;
find all files containing poster == find -name '*poster*' -type f
copy the directory path of the file and store it in a temporary variable and afterwards affix "folder.jpg" to directory path == -exec sh -c 'mv "{}" "$(dirname "{}")"/folder.jpg' \;

Related

How to exclude new lines (carriage returns) using find regex on GNU/Linux cli?

I'm trying to rename all files in a directory with de JPG extension to lowercase jpg.
I've made this bash code with the help of this post:
find . -regex ".*\.JPG" -exec sh -c 'echo "$0" | sed -r "s/\.JPG/\.jpg/" && mv "$0" "$1"' {} \;
But I get the following error:
./IMG_1352.jpg
mv: cannot move './IMG_1352.JPG' to '': No such file or directory
(and so on...)
I think I need to change names "places" but I don't know how.
TL;DR: Try this code:
find . -name '*.JPG' -type f -exec sh -c 'mv $0 ${0/.JPG/.jpg}' {} \;
More commentary:
Your code is pretty close to where it needs to be. There is an issue, however, in as much as $1 is not defined.
I ran the following code to figure out what value was going to be in $1.
$ ls
bye.jpg hi.JPG
$ find . -regex ".*\.JPG" -exec sh -c 'echo "$0" | sed "s/\.JPG/\.jpg/" && echo "0:$0 1:$1" ' {} \;
./hi.jpg
0:./hi.JPG 1:
According to my results above, there is no value in $1. You should be aware that $1 actually refers to the second parameter passed to the sh. That is, sh -c 'code' $0 $1 ...
Anyway, you'll need to capture the result of the sed command in a variable to pass it to the move command as follows:
find . -regex ".*\.JPG" -exec sh -c '
lower=$( echo "$0" | sed -r "s/\.JPG/\.jpg/" )
mv "$0" "$lower"
' {} \;
All that said, you could make this more concise. As PS suggests, the for loop is a good choice. Also, the JPG -> jpb replacement is more readable with PS's suggestion. If you are sold on using find, you can incorporate PS's suggestion as follows:
find . -regex ".*\.JPG" -exec sh -c '
filename=$0
mv "$filename" "${filename/.JPG/.jpg}"
' {} \;

linux find no such file or directory but exists

Then i trying to use this script
for line in `cat dirs.txt`;
do
find "$line" -type f \( -name '*good*' -o -exec grep -F "badbad" {} \; \) -exec echo {} \;;
done
I get error on each existing dirs and match the find criteria
find: /home/goods/ : No such file or directory
find: /home/bads/ : No such file or directory
find: /home/fill/ : No such file or directory
But then i look manualy this dirs exist and i can read them all
Why this happens?
You must check in file for ^M$
You can do that with command cat dirs.txt -vET
Then you must trim them all with command cat dirs.txt|tr -d "\r" >1.txt
Issue is that you have dos (^M) line endings, in the file. Running dos2unix dirs.txt dirs.txt should solve the problem. Ideally, you also shouldn't use for line in $(cat ..., but something like
while IFS= read -r line; do
find "$line" -type f \( -name '*good*' -o -exec grep -F "badbad" {} \; \) -exec echo {} \;
done < dirs.txt

Find files in multiple directories taken from list in a file?

FreeBSD 9.2 RELEASE p2
I have a file fromdirs.txt. In this file is a new line separated directory list like so:
/etc
/home
/home/goods/
I need to first find in all directory's files which have names like "good" or contain string "(NODES_'TASK')" and then copy all these files into the directory /tmp.
2.sh file chmod +x and is 755
fromDirs.txt file chmod +x and is 755
This code give me error
IFS=$'\n' read -d '' -r -a dirs < fromDirs.txt
find "${dirs[#]}" -type f \( -name '*good*' -o -exec grep -F "(NODES_'TASK')" {} \; \) -exec cp {} /tmp/ \;
2.sh: cannot open fromDirs.txt : No such file or directory
2.sh: ${dirs[...}: Bad substitution
But File fromDirs.txt exist and 2.sh running from it allocation directory, also i trying to provide full path instead of fromDirs.txt and error the same
This code give me error
FILE=fromDirs.txt
IFS='\n'
while read -r dirs
do
find "$dirs" -type f \( -name '*good*' -o -exec grep -F "(NODES_'TASK')" {} \; \) -exec cp {} /tmp/ \;
done < "$FILE"
2.sh: 6: Syntax error: "done" unexpected (expecting "do")
This code give me error too
FILENAME=fromDirs.txt
awk '{kount++;print kount, $0}
END{print "\nTotal " kount " lines read"}' $FILENAME
2.sh: : not found awk: can't open file fromDirs.txt source line number 2
So how to read file line by line and do what i need?
This works for me
for line in "`cat fromDirs.txt`"; do find "$line" -type f \( -name '*good*' -o -exec grep -F "(NODES_'TASK')" {} \; \) -exec cp {} /tmp/ \;; done

Pass a large variable into the diff command via bash

I am writing a script which does a checksum (md5sum) on a forum web directory.
It is a bash script. With the idea being to do a checksum on all the files in the directory, and then compare it to a text file which has a list of checksums.
The script works if I pass it into a text file, and then do a diff command between the text file and my list of known checksums, but I would like to not have it write to a text file and then have to remove the text file at the end of the script, hence why I am using a variable
The script below fails with the error:
/usr/bin/diff: Argument list too long
cd /var/www/html/forum/
VAR1=$(find . -type d \( -name store_sitemap \) -prune -o -type f -exec md5sum {} \; | grep -v "files\|that\|change")
/usr/bin/diff "${VAR1}" "/root/scripts/forum_checkum_original.txt"
How can I pass my variable along so that I can runn the diff command on it?
EDIT: with the help of the user devnull (thank you again) here is the completed and working script:
cd /var/www/html/forum/
MAIL=$(/usr/bin/diff <(find . -type d \( -name store_sitemap \) -prune -o -type f -exec md5sum {} \; | grep -v "files\|that\|change") /root/scripts/forum_checkum_original.txt)
if [[ -n $(/usr/bin/diff <(find . -type d \( -name store_sitemap \) -prune -o -type f -exec md5sum {} \; | grep -v "files that change") /root/scripts/forum_checkum_original.txt) ]]; then
echo "$MAIL" | mail -s "Forum Checksum" yourmailaddress#yourdomain.com
else
echo "no files have been changed"
fi
diff compares files, not variables. Use Process Substitution instead.
An equivalent of what you're trying to do would be:
/usr/bin/diff <(find . -type d \( -name store_sitemap \) -prune -o -type f -exec md5sum {} \; | grep -v "bidorbuy.log") /root/scripts/forum_checkum_original.txt
If you want to keep it in a variable you can give diff the variable as a filedescriptor by doing:
diff <(echo "$MAIL") "/root/scripts/forum_checkum_original.txt"

Include folder name in renaming a file in linux

I've already used that command to rename the files in multiple directories and change JPG to jpg, so I have consistency.
find . -name '*.jpg' -exec sh -c 'mv "$0" "${0%.JPG}$.jpg"' {} \;
Do you have any idea how to change that to include the folder name in the name of the file
I am executing that in a folder that contains about 2000 folders (SKU's) or products ... and inside every SKU folder, there are 9 images. 1.jpg 2.jpg .... 9.jpg.
So the bottom-line is I have 2000 images with name 1.jpg, 2.jpg ... 9.jpg. I need those files to be unique, for example:
folder-name-1.jpg ... folder-name.2.jpg ... so on, in every folder.
Any help will be appreciated.
For example I can do as follows:
$ find . -iname '*.jpg' | while read fn; do name=$(basename "$fn") ; dir=$(dirname "$fn") ; mv "$fn" "$dir/$(basename "$dir")-$name" ;done
./lib/bukovina/version.jpg ./lib/bukovina/bukovina-version.jpg
./lib/bukovina.jpg ./lib/lib-bukovina.jpg
You can use fine one-liner:
find . -name '*.jpg' -execdir \
bash -c 'd="${PWD##*/}"; [[ "$1" != "$d-"* ]] && mv "$1" "./$d-$1"' - '{}' \;
This command uses safe approach to check whether image name is already not prefixed by the current directory name. You can run it multiple times also and image name won't be renamed after first run.
To get the folder name of a file you can do $(basename $(dirname ${FILE})), where ${FILE} is a path that may be relative but must contain at least one folder before the file name in it. This should not be a problem with find. If it is, just run it from one directory up.
find . -name '*.jpg' -exec sh -c 'mv "$0" "$(basename $(dirname $0))-${0%.JPG}$.jpg"' {} \;
Or, if you have JPEGs in your current directory:
find ../<dirname> -name '*.jpg' -exec sh -c 'mv "$0" "$(basename $(dirname $0))-${0%.JPG}$.jpg"' {} \;

Resources