How can I make a copy of a file with a new name that contains the timestamp of the original in the filename? - linux

Writing a bash script that will copy a file into a directory where the new copy has the same name, but with the timestamp appended to the filename (prior to the extension).
How can I achieve this?

to insert the time stamp of the file itself into the original file name, as well as preserving that timestamp in the target file, the following works in GNU environments:
file="/some/dir/path-to-file.xxx";
cp -p "$file" "${file%.*}-$(date -r"$file" '+%Y%m%d-%H%M%S').${file##*.}"
Adding proper use of the basename(1) command into the mix would allow you to copy the file into a different directory.
It's more challenging to do this outside of GNU/Linux environments and you have to start visiting languages like awk, perl, python, even php, to replace the date -r command.

file="file_to_copy"
cp $file "/path/to/dest/$file"`stat --printf "%X" $file`
You can look at the manual page of stat (man 1 stat) to choose the appropriate timestamp for your needs (creation, last access etc.)
In this example, I chose %X which means time of last access, seconds since Epoch

Suppose
var="/path/to/filename.ext" #path is optional
Do
var1="${var##*/}
cp "$var" "/path/to/new/directory/${var1%.*}$(date +%s).${var1##*.}"
For more on ${var%.*} & ${var##*.} , see [ shell parameter expansion ].
date manpage says :
%s seconds since 1970-01-01 00:00:00 UTC

Related

Recursively replace linux file and folder names such as "%m-%d-%y.tar" with their actual creation month/day/year

I'm looking for something like this but with its original creation date instead of the current date.
Example: This folder (output below is from Linux command ls -ltr)
drwxrwxr-x 2 backup_user backup_user 4096 Apr 26 01:06 "%m-%d-%y"
would have its file name changed to "04-26-20".
Since there are some information missing I try to make assumptions and show a possible solution approach in general.
As already mentioned within the comments, for a filesystem like EXT3 there would be no creation time. It might be possible to use the modification time which could be gathered via the stat command, i.e.
MTIME=$(stat --format="%y" \"%m-%d-%y\" | cut -d " " -f 1)
... or even access time or change time.
The date of MTIME is given in format %Y-%m-%d and can be changed for the new file name via
FNAME=$(date -d ${MTIME} +%m-%d-%y)
Than it it is possible to rename the directory, i.e.
mv \"%m-%d-%y\" ${FNAME}
which will of course change the timestamps within the filesystem for the directory.

Rename file names in Linux based on conditions

I have some files in Linux directory like below.
email_Tracking_export_2018_08_26.zip
email_Tracking_export_2018_08_27.zip
email_Tracking_export_2018_08_28.zip
email_Tracking_export_2018_08_29.zip
email_Tracking_export_2018_09_03.zip
email_Tracking_export_history_Novemeber.zip
email_Tracking_export_history_December.zip
email_Tracking_export_history_january.zip
email_Tracking_export_history_february.zip
email_Tracking_export_history_march.zip
email_Tracking_export_history_April.zip
Now I want to change the files names to be like below.
email_Tracking_export_2018_08_26.zip
email_Tracking_export_2018_08_27.zip
email_Tracking_export_2018_08_28.zip
email_Tracking_export_2018_08_29.zip
email_Tracking_export_2018_09_03.zip
email_Tracking_export_2017_11_01.zip
email_Tracking_export_2017_12_01.zip
email_Tracking_export_2018_01_01.zip
email_Tracking_export_2018_02_01.zip
email_Tracking_export_2018_03_01.zip
email_Tracking_export_2018_04_01.zip
Conditions:
If the file names are in yyyy-mm-dd format then leave them as is
if the file names are in Alphabetical form convert to yyyy-mm-dd
if month has passed in that particular year than leave as is if not then year should be previous year.
How can I achive that in bash/Linux
for f in email_Tracking_export_*.zip; do
case "$f" in
email_Tracking_export_????_??_??.zip) : ignore ;;
*) date=$(stat -c %Y "$f") # mod time in seconds
fmtdate=$(date --date="#$date" +%Y_%m_%d) # formatted
mv "$f" email_Tracking_export_$fmtdate.zip
;;
esac
done
Here are the steps in small parts which you can find answers of and execute as a bash script,
Make a key value pair of mapping, which maps a month to its numerical value. (Take care of lowercase/uppercase)
For each file, check their format.
Generate the new name for each file.
Then, use the mv command to rename the file with the new name.

Find and Replace in bash Shell

Please advise on replacing a variable with latest date & time.
Here is my requirement.
FN='basename$0'
TS=`date '+%m/%d/%Y %T'`
QD='08/27/2014 16:25:45'
Then I have a query to run. After it has run, I need to take $TS (current system date & time) and assign it as a value to the $QD variable. This is a loop process and gets updated every time the script runs.
I've tried using sed but was not successful.
Please help.
Programatically modifying your script to have a different timestamp constant is absolutely and emphatically the wrong way to handle this problem.
Instead, when you want to mark that the query has been done, simply touch a file:
touch lastQueryCompletion
...and when you want to know when the query was last done, check that file's timestamp:
# with GNU date
QD=$(date -r lastQueryCompletion '+%m/%d/%Y %T')
# or, with Mac OS X stat
QD=$(stat -t '%Y/%m/%d %H:%M:%S' -f '%Sm' lastQueryCompletion)
Although you haven't mentioned the overall goal that you wish to accomplish, I have a feeling something like this would be more robust than using sed to update an existing script file.
FN='basename$0'
TS=date '+%m/%d/%Y %T'
# Load the latest QD (from the last run)
[ -e ~/.QD.saved ] && QD="`cat ~/.QD.saved`"
QD='08/27/2014 16:25:45'
...Later in that file...
#Save the new QD variable
echo '$(date +$FORMAT)'" > ~/.QD.saved
Although I'm not sure if sed is the tool you're looking, I believe that your command would have to go like this:
sed -i -r 's/^QD=.*/QD="$TS"/g' "$FN"
I'm assuming you're using gnu-sed, which with -i option tells to do an in-place substitution, rather then copying the input line to the pattern space.
Well, hope it helps.

Send previous day file to server in unix

I'm devloping a shell script to scp a.txt to different servers(box1 and box2) and script is running in boxmain server. Below are the requirements,
my script will connect to db2 database and generate a.txt file in boxmain
a.txt will be scp'ed to box1 once the file is generated
The file generated in boxmain(a.txt) will be scp'ed to box2 on the next day, i.e. It will be an SCP of the previous day's boxmain file
Note : box1,box2,boxmain are servers
i tried the below, able to finish first 2 tasks but stuck in 3rd. Please suggest how to achieve the third point. Thanks in advance.
db2 -tvf query.sql #creates a.txt
scp a.txt user#box1:/root/a.txt
now=$(date +"%m/%d/%Y")
cp a.txt a_$now.txt
my os version is AIX test 1 6
There is a slight problem with your question definition: using '/' in the name of your source filename will make it interpreted as not just a filename but a path containing directories as well because '/' is the directory separator. It might be a good idea to use now=$(date +"%m-%d-%Y") instead of now=$(date +"%m/%d/%Y").
But to answer your actual problem which I think boils down to this: how to get date(1) to output a date from yesterday on AIX?
The answer was found from The UNIX and Linux Forums: just set the environment variable describing your timezone to have +24 in it and you'll get yesterdays date from output of date.
For example:
user#foo ~]# date
Mon Nov 4 09:40:34 EET 2013
user#foor ~]# TZ=EST+24 date
Sun Nov 3 07:40:36 EST 2013
Applying this to your problem, just set an appropriate value for TZ when you run now=$(date +"%m/%d/%Y") ie. use now=$(TZ=ZONE+24 date +"%m-%d-%Y") (note the corrections on the path separator and replace ZONE with your own timezone).

filename last modification date shell in script

I'm using bash to build a script where I will get a filename in a variable an then with this variable get the file unix last modification date.
I need to get this modification date value and I can't use stat command.
Do you know any way to get it with the common available *nix commands?
Why you shouldn't use ls:
Parsing ls is a bad idea. Not only is the behaviour of certain characters in filenames undefined and platform dependant, for your purposes, it'll mess with dates when they're six months in the past. In short, yes, it'll probably work for you in your limited testing. It will not be platform-independent (so no portability) and the behaviour of your parsing is not guaranteed given the range of 'legal' filenames on various systems. (Ext4, for example, allows spaces and newlines in filenames).
Having said all that, personally, I'd use ls because it's fast and easy ;)
Edit
As pointed out by Hugo in the comments, the OP doesn't want to use stat. In addition, I should point out that the below section is BSD-stat specific (the %Sm flag doesn't work when I test on Ubuntu; Linux has a stat command, if you're interested in it read the man page).
So, a non-stat solution: use date
date, at least on Linux, has a flag: -r, which according to the man page:
display the last modification time of FILE
So, the scripted solution would be similar to this:
date -r ${MY_FILE_VARIABLE}
which would return you something similar to this:
zsh% date -r MyFile.foo
Thu Feb 23 07:41:27 CST 2012
To address the OP's comment:
If possible with a configurable date format
date has a rather extensive set of time-format variables; read the man page for more information.
I'm not 100% sure how portable date is across all 'UNIX-like systems'. For BSD-based (such as OS X), this will not work; the -r flag for the BSD-date does something completely different. The question doesn't' specify exactly how portable a solution is required to be. For a BSD-based solution, see the below section ;)
A better solution, BSD systems (tested on OS X, using BSD-stat; GNU stat is slightly different but could be made to work in the same way).
Use stat. You can format the output of stat with the -f flag, and you can select to display only the file modification data (which, for this question, is nice).
For example, stat -f "%m%t%Sm %N" ./*:
1340738054 Jun 26 21:14:14 2012 ./build
1340738921 Jun 26 21:28:41 2012 ./build.xml
1340738140 Jun 26 21:15:40 2012 ./lib
1340657124 Jun 25 22:45:24 2012 ./tests
Where the first bit is the UNIX epoch time, the date is the file modification time, and the rest is the filename.
Breakdown of the example command
stat -f "%m%t%Sm %N" ./*
stat -f: call stat, and specify the format (-f).
%m: The UNIX epoch time.
%t: A tab seperator in the output.
%Sm: S says to display the output as a string, m says to use the file modification data.
%N: Display the name of the file in question.
A command in your script along the lines of the following:
stat -f "%Sm" ${FILE_VARIABLE}
will give you output such as:
Jun 26 21:28:41 2012
Read the man page for stat for further information; timestamp formatting is done by strftime.
have perl?
perl -MFile::stat -e "print scalar localtime stat('FileName.txt')->mtime"
How about:
find $PATH -maxdepth 1 -name $FILE -printf %Tc
See the find manpage for other values you can use with %T.
You can use the "date" command adding the desired format option the format:
date +%Y-%m-%d -r /root/foo.txt
2013-05-27
date +%H:%M -r /root/foo.txt
23:02
You can use ls -l which lists the last modification time, and then use cut to cut out the modification date:
mod_date=$(ls -l $file_name | cut -c35-46)
This works on my system because the date appears between columns 35 to 46. You might have to play with it on your system.
The date is in two different formats:
Mmm dd hh:mm
Mmm dd yyyy
Files modified more than a year ago will have the later format. Files modified less than a year ago will have to first format. You could search for a ":" and know which format the file is in:
if echo "$mod_date" | grep -q ":"
then
echo "File was modified within the year"
else
echo "File was modified more than a year ago"
fi

Resources