I have a directory of files that I need to rename to a given string with a timestamp.
I use the following code:
for file in itvl_*
do
mv "$file" "Interval_$(stat -c %Y "$file" | date +%Y%m%d%H%M%S).Interval_001"
done
When I run the script in a directory of files that fit the given mask itvl_*, it removes all but one or two of the files and then successfully renames the last file in the group.
What might be happening here?
It doesn't delete all the files, it simple renames all of them to the same target name.
You can see it by running:
for file in itvl_*
do
echo "Interval_$(stat -c %Y "$file" | date +%Y%m%d%H%M%S).Interval_001"
done
The result is that they override one another and only the last one survives.
Related
I have the following bash script I've been using to set the "last modified" date of all selected files to that of the oldest file selected.
oldest=$(stat -f "%m:%N" "$#" | sort -n | head -1 | cut -f2 -d:)
for f in "$#"; do
touch -hr "$oldest" "$f"
done
I've also got the following script to determine the original "file.lua" when the "file copy.lua" is selected in Finder, and echo both the original and the copy.
for f in "$#"; do
echo "$f"
echo "$f" | sed 's/ copy\.lua/\.lua/g'
done
I tried setting it up in automator as two "Run Shell Script" actions: the first one being the one that gets the original files from the names of the selected file copies, followed by the one that changes the modification date. But with multiple copied files selected, the script will instead set all of the selected copied files and their originals to the oldest modification date of all the files being processed.
How can I change this so that each file copy and its original are processed as a pair rather than all of the selected file copies and their originals being processed as a group?
The purpose of this is so that I can make minor/arbitrary comment or variable name changes to numerous lua files without altering their modification date, since I use modification date to organize files based on updates to the actual scripts in the files. The idea is, once I find all of the files I want to make the minor changes to, I first make a copy of them all that will retain the current modification date. Then, after making the changes and saving them all, with the file copies still selected in Finder, I run this service to restore the modification dates of the files from their copies, and then delete all the copies.
I really hope there's a simple solution for this. I've been racking my brain trying to figure it out for way too many hours now.
I have a set of files that are organised across a large number of sub-directories, for example:
/Image/Square001/Data
/Image/Square002/Data
/Image/Square003/Data
and so on.
All the files within these directories have a similar type of name but have different numbers within the name.
Triangle_284852_Data_222844_222846_20220302_034926.tiff
Triangle_284908_Data_222841_222843_20220302_035350.tiff
Triangle_284908_Data_222845_222843_20220302_035350.tiff
I had like to rename all of these files to include another number. The correct number needed has already been appended to a given filename within a text file (temp_names.txt)
Triangle_284852_Data_222844_222846_20220302_034926_1.tiff
Triangle_284908_Data_222841_222843_20220302_035350_63.tiff
Triangle_284908_Data_222845_222843_20220302_035350_12.tiff
I am trying to write a bash script to rename the files in the directory to match those in temp_names.txt
I think I need to use the find command, set up a while loop for each file to be matched based on their similarity and be renamed, but I am having trouble getting this right.
In the past, I have used something like:
for file in ./Image/Square*/Data/*.tiff
do
read line
mv "${file}" "${line}"
done < temp_names.txt
When the files are all in the same sub-directory and are read in the same order as they appear in my text file. However, this is not the case for these files and I need a new approach. I have been trying some variants of starting like this:
find /Images/Square*/Data/ -type f -name .tiff |
while IFS= read -d '' file_name; do
But I am unsure whether I should be using rename or mv in the next line, how to match the common parts between the filename in the directory and in the text file, and then how to add a changeable string (the number at the end) to the file name.
This is a script to do your requirement:
#!/bin/bash
find . -type f -name "Triangle_*.tiff" -print0 | while IFS= read -r -d '' file
do
# extract the filename, without extension
filename=$(basename "${file%.*}")
# Find that in the temp_names.txt file
newfilename=$(grep "$filename" temp_names.txt)
# extract the path of the file
filepath=$(dirname "$file")
# rename the file
mv -v "$file" "$filepath/$newfilename"
done
The find is recursive, so it will handle all files.
From each file, remove its extension, then grep for the name in the list of new filenames.
Since the file could be in any sub-directory, the path is extracted from the file found by find.
The mv changes the name of the file to the new name, under the same directory as the original file.
I put option -v to the mv to get some log of what is done. But you can remove it if not required.
I want to batch rename some file based of Part of Name of other files
let me explain my question with a example, I think its better in this way
I have some file with these name in a folder
sc_gen_08-bigfile4-0-data.txt
signal_1_1-bigfile8.1-0-data.txt
and these file in other folder
sc_gen_08-acaaf2d4180b743b7b642e8c875a9765-1-data.txt
signal_1_1-dacaaf280b743b7b642e8c875a9765-4-data.txt
I want to batch rename first files to name of second files, how can I do this? also file in both first and second folder have common in name
name(common in file in both folder)-[only this part is diffrent in each file]-data.txt
Thanks (sorry if its not a good question for everyone, but its a question for me)
Let's name the original folder as "folder1" and the other folder as "folder2". Then would you please try the following:
#!/bin/bash
folder1="folder1" # the original folder name
folder2="folder2" # the other folder name
declare -A map # create an associative array
for f in "$folder2"/*-data.txt; do # find files in the "other folder"
f=${f##*/} # remove directory name
common=${f%%-*} # extract the common substring
map[$common]=$f # associate common name with full filename
done
for f in "$folder1"/*-data.txt; do # find files in the original folder
f=${f##*/} # remove directory name
common=${f%%-*} # extract the common substring
mv -- "$folder1/$f" "$folder1/${map[$common]}"
# rename the file based on the value in map
done
If your files are all called as you mentioned. I have created the next script.
It is located following the next structure.
root#vm:~/test# ll
folder1/
folder2/
script.sh
The script is the next:
#Declare folders
folder1=./folder1
folder2=./folder2
#Create new folder if it does not exist
if [ ! -d ./new ]; then
mkdir ./new;
fi
#Iterate over first directory
for file1 in folder1/*; do
#Iterate over second directory
for file2 in folder2/*; do
#Compare begining of each file, if they match, they will be copied.
if [[ $(basename $file1 | cut -f1 -d-) == $(basename $file2 | cut -f1 -d-) ]]; then
echo $(basename $file1) $(basename $file2) "Match"
cp folder1/$(basename $file1) new/$(basename $file2)
fi
done
done
It creates a folder called new and will copy all your files there. If you want to delete them, use mv instead. But I didn't want to use mv in the first attempt just in case to get some undesired effect.
I'm processing a large collection of born-digital materials for an archive but I'm being slowed down by the fact that I'm having to manually create directories and find and move files from multiple directories into newly created directories.
Problem: I have three directories containing three different types of content derived from different sources:
-disk_images -evidence_photos -document_scans
The disk images were created from CDs that come with cases and writing on the cases that need to be accessible and preserved for posterity so pictures have been taken of them and loaded into the evidence photos folder with a prefix and inventory number. Some CDs came with indexes on paper and have been scanned and OCR'd and loaded into the document scan folder with a prefix and an inventory number. Not all disk images have corresponding photos or scans so the inventory numbers in those folders are not linear.
I've been trying to think of ways to write a script that would look through each of these directories and move files with the same suffix (not extension) to newly created directories for each inventory number but his is way beyond my expertise. Any help would be much appreciated and I will be more than happy to clarify if need be.
examples of file names:
-disk_images/ahacd_001.iso
-evidence_photos/ahacd_case_001.jpg
-document_scans/ahacd_notes_001.pdf
Potential new directory name= ahacd_001
There all files with inventory number 001 would need to end up in ahacd_001
Bold= inventory number
Here is a squeleton of program to iterate through your 3 starting folders and split your file names:
for folder in `ls -d */` #list directories
do
echo "moving folder $folder"
ls $folder | while read file # list the files in the directory
do
echo $file
# split the file name with awk and get the first part ( 'ahacd' ) and the last ('002')
echo $file | awk -F '.' '{print $1}' |awk -F '_' '{print $1 "_" $NF}'
# when you are statisfied that your file splitting works...
mkdir folder # create your folder
move file # move the file
done
done
A few pointers to split the filenames :
Get last field using awk substr
First I would like to say that file or directory names starting with - is a bad idea even if it's allowed.
Test case:
mkdir -p /tmp/test/{-disk_images,-evidence_photos,-document_scans}
cd /tmp/test
touch -- "-disk_images/ahacd_001.iso" #create your three test files
touch -- "-evidence_photos/ahacd_case_001.jpg"
touch -- "-document_scans/ahacd_notes_001.pdf"
find -type f|perl -nlE \
'm{.*/(.*?)_(.*_)?(\d+)\.}&&say qq(mkdir -p target/$1_$3; mv "$_" target/$1_$3)'
...will not move the files, it just shows you what commands it thinks should be runned.
If those commands is what you want to be runned, then run them by adding |bash at the end of the same find|perl command:
find -type f|perl -nlE \
'm{.*/(.*?)_(.*_)?(\d+)\.}&&say qq(mkdir -p target/$1_$3; mv "$_" target/$1_$3)' \
| bash
find -ls #to see the result
All three files are now in the target/ahacd_001/ subfolder.
I am writing a Bash script that will replace files in folder A (source) with folder B (target). But before this happens, I want to record 2 files.
The first file will contain a list of files in folder B that are newer than folder A, along with files that are different/orphans in folder B against folder A
The second file will contain a list of files in folder A that are newer than folder B, along with files that are different/orphans in folder A against folder B
How do I accomplish this in Bash? I've tried using diff -qr but it yields the following output:
Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ
I've also tried this
(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq
but it doesn't give me the scope of results I require. The struggle here is that the data isn't in the correct format, I just want files not directories to show in the text files e.g:
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php
List of files in directory B (new/) that are newer than directory A (old/):
find new -newermm old
This merely runs find and examines the content of new/ as filtered by -newerXY reference with X and Y both set to m (modification time) and reference being the old directory itself.
Files that are missing in directory B (new/) but are present in directory A (old/):
A=old B=new
diff -u <(find "$B" |sed "s:$B::") <(find "$A" |sed "s:$A::") \
|sed "/^+\//!d; s::$A/:"
This sets variables $A and $B to your target directories, then runs a unified diff on their contents (using process substitution to locate with find and remove the directory name with sed so diff isn't confused). The final sed command first matches for the additions (lines starting with a +/), modifies them to replace that +/ with the directory name and a slash, and prints them (other lines are removed).
Here is a bash script that will create the file:
#!/bin/bash
# Usage: bash script.bash OLD_DIR NEW_DIR [OUTPUT_FILE]
# compare given directories
if [ -n "$3" ]; then # the optional 3rd argument is the output file
OUTPUT="$3"
else # if it isn't provided, escape path slashes to underscores
OUTPUT="${2////_}-newer-than-${1////_}"
fi
{
find "$2" -newermm "$1"
diff -u <(find "$2" |sed "s:$2::") <(find "$1" |sed "s:$1::") \
|sed "/^+\//!d; s::$1/:"
} |sort > "$OUTPUT"
First, this determines the output file, which either comes from the third argument or else is created from the other inputs using a replacement to convert slashes to underscores in case there are paths, so for example, running as bash script.bash /usr/local/bin /usr/bin would output its file list to _usr_local_bin-newer-than-_usr_bin in the current working directory.
This combines the two commands and then ensures they are sorted. There won't be any duplicates, so you don't need to worry about that (if there were, you'd use sort -u).
You can get your first and second files by changing the order of arguments as you invoke this script.