Bash script to find .jpgs created within a certain time frame and then rename them - linux

I have the following find command working pretty well which walks through a directory tree looking for any .jpg it finds with a file modification date of 600 minutes or less:
find /some/directory/ -depth -mmin -600 -name *.jpg
What I need to do now is rename all the .jpg it finds to the actual creation date that the .jpg was created on and create some random numbers at the end of the file before appending .jpg back to it. I've used this in the past: (date -r "$f" +%Y-%m-%d_%H-%M-%S-%N).jpg but I can't seem to figure out how to tie the find to the mv.
Am I missing a simple way to do this with -exec?

This should achieve what you wanted :
find /some/directory/ -depth -mmin -600 -name "*.jpg" \
-exec bash -c 'echo mv "$1" "$(dirname "$1")/$(date -r "$1" +%Y-%m-%d_%H-%M-%S-)$(date +%N).jpg"' bash {} \;
Remove echo to do renaming once you are satisfied with result.

Related

Using find to rename files recursively with random chars

I have an IP camera that takes snapshots and nests those snapshots into multiple directories. The sub directories look something like this.
/cam_folder
|--Date
|----Hour
|------Minute
|-------->file1
|-------->file2...etc
|------Minute
|-------->file1...etc
There is a ton of sub directories because of the way it stores files since it places those snapshots within a Minute directory of the Date/Hour directories.
At any rate, there are other types of files mixed in, but I know how to use find to find all the .jpgs I need:
find /cam_folder/ -type f -name '*.jpg'
But what I need to do is rename all the .jpg files to random characters. I was able to find this which works from a single directory in a bash script:
for file in *.jpg; do
new_file="$(mktemp XXXXXXXX.jpg)"
mv -f -- "$file" "$new_file"
done
My problem is how to tie these together? I need to use find to feed these into a bash script I guess?
Is there an easier way to just walk a directory recursively renaming as I go?
find /cam_folder/ -type f -name '*.jpg' -exec sh -c '
for f; do
mv -f -- "$f" "${f%/*}/$(mktemp -u XXXXXXXX.jpg)"
done' _ {} +
find
Shell Command Language § The for Loop
Shell Command Language § Parameter Expansions
I think that meets your demand
while IFS= read -r file ; do
new_file="$(mktemp XXXXXXXX.jpg)"
mv -f -- "$file" "$new_file"
done < <(find /cam_folder/ -type f -name '*.jpg')

Creating a file in a directory other than root using bash

I am currently working on an auto grading script for a class project. It has to be able to search any number of given directories lets say
for example
usr/autograder/jdoe/
jdoe contains two files house.c and readme.txt.
I need to create a file in jdoe called jdoe.pdf
Currently i'm using this line of code below to get the path to where i need to create the file. Where $1 is user input of the path containing the projects the auto grader will grade.
find $1 -name "*.txt" -exec sh -c "dirname {}"
When I try adding /somename.pdf to the end of this statement I get readme.txt/somename.pdf
along with another -exec to get the name for the file.
\; -exec sh -c "dirname {} xargs -n 1 basename" \;
I'm having problems combining these two into one working statement.
I'm new to unix programming and would appreciate any advice or help even if it means re-writing the code using different unix tools.
The main question here is how do I create files in a path other than the directory I call my script from. Thanks in advance.
How about this?
find "$1" -name "*.txt" -exec bash -c 'd=$(dirname "$1"); touch $d"/"$(basename "$d").pdf' - {} \;
You can create files in another path using change directory command (cd).
If you start your script in usr/autograder/script and want to change to usr/autograder/jdoe you can change directory with shell command cd ../jdoe (relative) or cd usr/autograder/jdoe (absolute).
Now you are in the directory of usr/autograder/jdoe and you are able to create files in this directory, for example gedit readme.txt will open gedit and creates the file in usr/autograder/jdoe.
The simplest way is to loop over the files returned by find and then do whatever you need to do.
For example:
find "$1" -type f -name "*.txt" -print0 | while IFS= read -r -d $'\0' filename; do
dir=$(dirname "$filename")
# create pdf file
touch "$dir/${dir##*/}.pdf"
done
(Note the use of find -print0 to correctly handle filenames containing whitespace and newline characters.)
Is this what you are looking for?
function process_file {
dir=$(dirname "$1")
name=$(basename "$1")
echo name is $name and dir is $dir;
cd "$dir"
touch "${dir##*/}.pdf" # or anything else
}
# export the function, so that it is known in the child processes
export -f process_file
find . -name '*.txt' -exec bash -c "process_file '{}'" \;

Embedding a bash command inside the mv command

I have a directory that contains a list of files having the following format:
240-timestamp1.ts
240-timestamp2.ts
...
360-timestamp1.ts
360-timestamp2.ts
Now, I want to implement a bash command which matches the files that start with '240' and renames them so that instead of '240-timestampX.ts' the files look like '240-human-readable-timestampX.ts'.
I have tried the following:
find . -maxdepth 1 -mmin +5 -type f -name "240*"
-exec mv $0 {$0/240-***and here I want to insert
either stat -c %y filename or date -d #timestampX***} '{}' \;
I stuck here because I don't know if I can embed a bash command inside the mv command. I know the task may look a bit confusing and over-complicated, but I would like to know if it is possible to do so. Of course I can create a bash script that would go through all the files in the directory and while loop them with changing their respective names, but somehow I think that a single command would be more efficient (even if less readable).
The OS is Linux Ubuntu 12.04.5
The shell is bash
Thank you both Kenavoz and Kurt Stutsman for the proposed solutions. Both your answers perform the task; however, I marked Kenavoz's answer as the accepted one because of the degree of similarity between my question and Kenavoz's answer. Even if it is indeed possible to do it in a cleaner way with omitting the find command, it is necessary in my case to use the respective command because I need to find files older than X units of time. So thank you both once again!
In case you want to keep your mmin option, your can use find and process found files with a bash command using xargs :
find . -maxdepth 1 -mmin +5 -type f -name "240*.ts" | xargs -L 1 bash -c 'mv "${1}" "240-$(stat -c %y ${1}).ts"' \;
In bash if all your files are in a single directory, you don't need to use find at all. You can do a for loop:
for file in 240-*; do
hr_timestamp=$(date -d $(echo "$file" | sed 's/.*-\([0-9]*\)\.ts/\1/'))
mv "$file" "240-$hr_timestamp.ts"
done

Renaming ID3 tag in Bash script with eyeD3

I have the following script that finds any file with the .mp3 extension in the incoming directory and moves it to the complete directory - it works perfectly!
#!/bin/bash
find /usr/audio/incoming -name '*.mp3' -exec mv {} /usr/audio/complete \;
exit
Now, I've installed eyeD3 (http://eyed3.nicfit.net/index.html) and I'm attempting to rename the Title tag somewhere during this entire process before it gets moved to the complete directory.
I've tried the following (and many more) but none of them work at all:
Trying to do it all in the same line...
#!/bin/bash
find /usr/audio/incoming -name '*.mp3' eyeD3 -t "New Title" -exec mv {} /usr/audio/complete \;
exit
Trying to do it by splitting it up...
#!/bin/bash
cd /usr/audio/incoming eyeD3 -t "New Title" '*.mp3';
find /usr/audio/incoming -name '*.mp3' -exec mv {} /usr/audio/complete \;
exit
Even just trying to get eyeD3 to rename the tag and nothing else...
#!/bin/bash
cd /usr/audio/incoming eyeD3 -t "New Title" '*.mp3';
exit
I know that i'm doing something wrong, but I've searched high and low and there is virtually zero newbie support for eyeD3 that I can find. What there is out there tends to be for python scripts that don't really do what I need anyway.
Does anybody know where I'm going wrong here?
For clarity, I want to rename the tag of every single mp3 file in this directory with the same title, but all of the mp3s have different file names, which is why I'm using the wildcard instead of the file name. Maybe I'm doing this the wrong way?
I think this will work:
find /usr/audio/incoming -name '*.mp3' -exec eyeD3 -t 'New Title' '{}' \; -exec mv '{}' /usr/audio/complete \;

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