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
Related
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.
I have an actioncam that saves my video in a folder into the SD Card.
Using linux, here is the path:
/media/mattiapdo/EOS_DIGITAL/_REC/100MEDIA
Files are saved in the REC_0001.AVI format
I would write a script that renames each file using the writing date.
Furthermore I notice that for some strange reason, the date and the hour are different from the effective: for example, 12/07/2017 10:30 is written as 09/02/2011 07:55
As the camera is very old and minimal, I can't reset the correct date and the correct hour so I would prefer to manipulate them in aftermath.
The goal would be to rename REC_0001.AVI in 2017_07_12__10_30.AVI
Does anyone have any ideas?
You can use the date command to print the elapsed seconds since, Unix lingo, the Epoch, aka 1970-01-01 UTC. Assuming that the camera date is in Anglo format, and that by default date likes the Anglo format, you have to swap the month and day in your date
$ date --date='09/02/2011 07:55' +%s
1314942900
$ date --date='07/12/2017 10:30' +%s
1499848200
$
so that you can compute a Delta between the real date and the camera idea of time
$ Delta=$(($(date --date='07/12/2017 10:30' +%s)-$(date --date='02/09/2011 07:55' +%s)))
$ echo $Delta
184905300
$
You haven't (yet?) told us how you fetch the date from the camera, but let's
say that
$ camera=$(fetch_date $current_file_name)
and assuming that $camera is in a format that date likes,
$ fromEpoch=$(($(date --date="$camera" +%s)+$Delta))
the last step is to get back the date in a format that you like , I suggest
the ISO 8601 format, so that your files are correctly sorted by ls
$ corrected_date=$(date --date="#$fromEpoch" +%Y-%m-%dT%H:%M)
$ cp $current_file_name other_directory/$corrected_date.AVI
The boring details about the date command, that is indeed VERY flexible and useful, are available using
$ man date
I hope that you can write your script with the info that I gave you, thank you for the question.
Addendum
Caveat emptor: totally untested
$ cat script
Delta=$(($(date --date='07/12/2017 10:30' +%s)-$(date --date='02/09/2011 07:55' +%s)))
mkdir -p ATTIC
mv *AVI ATTIC
for file in ./ATTIC/*.AVI ; do
########## fetch_date command is a placeholder for the real command
cam_date=$(fetch_date "$file")
cam_fromEpoch=$(date --date="$cam_date" +%s)
correct_fromEpoch=$(($cam_fromEpoch+$Delta))
ISO_8601=$(date --date="#$correct_fromEpoch" +%Y-%m-%dT%H:%M)
cp $file $ISO_8601.AVI
done
# cleanup, e.g. list current directory and ATTIC and ask if ATTIC is to be removed
$
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
I want to use the find command to find these directories:
Access: 2013-12-13 10:59:46.190886900 -0500
Modify: 2013-12-03 07:04:02.995890600 -0500
Change: 2013-12-03 07:04:02.995890600 -0500
Birth: 2013-12-02 07:04:02.000000000 -0500 (I want a time after '12-03')
This is the command I ran but it still lists older directories:
find . -type d -newerBt '2013-12-03 00:00:00' -exec du -h {} \;
How can I modify this line to find the directories created after that date? What is the difference between -newerct and -newerBt. I think I want the birth date.
Note: I am running this with the latest cygwin.
You could use stat instead:
find . -type d -exec bash -c '(( $(stat -c %W "{}") > $(date +%s -d '2013-12-03') )) && du -h "{}"' \;
You are finding directories, but showing files contained therein.
Those files may have birth dates that lie before that of the containing directory. For example, create a file, then a directory, and move the file into that directory.
This is the difference between birth date and change date. If a file is moved into the dir, the dir is changed, so I think -newerct is what you want.
I wonder if it's a TimeZone issue? What is echo $TZ? What happens if you do unset TZ (and unsetenv TZ, too, in csh) and re-try the same commands?
Here's the man page excerpt for -newerXY. Maybe reading it will trigger some thoughts?
-newerXY reference
Compares the timestamp of the current file with reference. The reference
argument is normally the name of a file (and one of its timestamps is used
for the comparison) but it may also be a string describing an absolute time.
X and Y are placeholders for other letters, and these letters select which
time belonging to how reference is used for the comparison.
a The access time of the file reference
B The birth time of the file reference
c The inode status change time of reference
m The modification time of the file reference
t reference is interpreted directly as a time
Some combinations are invalid; for example, it is invalid for X to be t.
Some combinations are not implemented on all systems; for example B is not
supported on all systems. If an invalid or unsupported combination of XY is
specified, a fatal error results. Time specifications are interpreted as for
the argument to the -d option of GNU date. If you try to use the birth time
of a reference file, and the birth time cannot be determined, a fatal error
message results. If you specify a test which refers to the birth time of
files being examined, this test will fail for any files where the birth time
is unknown.
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).