Getting the name of the folder and comparing to integer in bash - bash

Ok, so what I'm trying to do is, all my backup folders are named dates 03-07-13. So I'm trying to select the day, and if it's greater than or equal to 7 days old, it will delete. This is what I have so far, but it's not working.
DATE=$(date +"%d")
for i in /media/backupdrive/*; do
DAY=${i:22:2}
if [ "$DAY" -ge "7" ]
then
echo "day greater than 7";
fi
done
the 22:2 cuts off the /media/backupdrive/00-
00 represents the month
Right now It's just checking if it's greater than 7, if it is, it prints it out.
EDIT: The problem was resolved. I want to thank you all for helping a bash beginner. Thank you again!

Per a screenshot given in a comment, your actual code uses the following:
DAY=${i:22:2}
if [ "$day" -ge "7" ]
Emphasis on the capitalization-differences between DAY and $day. When this runs, it's trying to compare an empty-string to a string (or "numbers" via the -ge) and this will cause the error you're receiving.
Try updating your if statement to use the uppercase version:
if [ "$DAY" -ge "7" ]

It seems you want to delete files that are older than 7 days. The find command can find those files for you, and optionally delete them:
find /media/backupdrive -mtime +7 # Files that are older than 7 days
find /media/backupdrive -mtime +7 -delete # ... and delete them

Using the 'DAY' variable opens you up to "just rolled over" issues.
Some alternatives:
change the folder format so that it is more descriptive.
add a meta file in each folder that gives a time value that is easier to parse and work with.
have an index for the backup folders containing said data.
The time format I generally use incorporates the following:
[epoch seconds]-[YYYY][MM][DD]-[HH]:[MM]:[SS]
This lets you do things like asking for backups that are 7 days old from right now. You would do the math against the epoch seconds, which avoids the confusion of days rolling over.
Basically, the epoch seconds is for making time calcs easier. The other time stamp bits makes it human readable. The ordering makes it so that it sorts correctly in a folder listing.
EDIT:
In the event your backup path ever changes:
DAYtmp=${i: -8:5}
DAY=${DAYtmp: -2}
This will yield the DAY from the folder name if the parent paths change in length.

Related

How do I change the order of a filename on Mac

I've got a folder with a number of files in the following format:
Photo 31-12-2020, 00 08 09.jpg
i.e. dd-mm-yyyy, hr min sec.jpg
I would like to rename them all files to the following format:
2020-12-31 00.08.09.jpg
i.e. yyyy-mm-dd hr.mm.sec.jpg
The changes are: year and day moved around, comma removed, dots between hours, minutes and seconds.
However, there are a couple of hundred of files in the folder, so I would like to automate this with a bash script.
I have looked into running a bash script to do this, but I’m unfortunately not very comfortable with scripting and wasn’t successful.
Could anyone help me find an easy method to resolve my issue?
Assuming you're in the directory in which the photos are .... this should work.
for i in Photo*jpg
do
echo mv -v "${i}" "$(echo $i|awk 'BEGIN{FS="[ ,.-]"}{printf "%s-%s-%s %s.%s.%s.jpg\n",$4,$3,$2,$6,$7,$8}')"
done
... if the output looks sensible, trim out the first echo ..

Calculating days left to a specific date

I'm having trouble figuring out a way to calculate amount of days left to a specific date (passed as an argument). I tried this, however it doesn't even work correctly with any date of 2021.
days=$[$(date +%j -d $1)-$(date +%j $now)];
if (( $days < 0 ))
then
echo "error";
exit 1;
fi
echo "Theres" $days "left to this date.";
Does anyone have an idea on how I could fix it?
There are a few problems I see.
I don't recognize the $[...] syntax and can't find a shell that does (see the comments, below, where user #KamilCuk explains this further).
The if syntax is wrong, possibly swapped with the previous line.
Because of the parentheses, what's read as a less-than sign (<) is going to try to redirect input to a program.
The answer will always print out.
As you point out, there's no chance of a Julian day working with different years.
Try something like this, instead.
#!/bin/sh
Split up the dates for easier debugging, first, and also use `+%s to get "UNIX time" seconds since the start of 1970.
now=$(date +%s $now)
target=$(date +%s -d $1)
days=$(($target - $now));
Fix the conditional syntax.
if [ $days -lt 0 ]
then
echo error
exit 1
Put the output into an else clause.
else
Since we have the answer in seconds, divide by the number of seconds in a typical day.
days=$(($days / 86400))
echo "There are $days days left to this date."
fi
I also cleaned up the echo syntax for clarity.
Note that this still isn't perfect. Depending on your definition of "one day," there are going to be cases where the answer from this script differs from what you want; in that case, you'll need to adjust $target to match a particular time of day. In addition, not every day is 86400 seconds long, because of daylight savings and leap seconds. But with those caveats, it should work well enough and adding those to a script sounds like more work than "how many days?" should warrant.
If you want to see the steps it takes for debugging, run it with sh -x date.sh '2022-12-31' (with your script's name and date), since the -x argument tells the shell to give you a "trace" of intermediate steps.

Rename file from Day of the Year to YYMMDD0000

I have a file with this name
ims2015255_4km_GIS_v1.3.png so it shows the 255 day of year 2015.
I want to auto rename this file to read like this
SNC_obs_YYMMDD0000.png The time to be always 0000
Thanks a lot.
Parsing the original name is fairly easy.
input=ims2015255_4km_GIS_v1.3.png
[[ $input =~ ims(....)(...)_ ]] && year=${BASH_REMATCH[1]} day=${BASH_REMATCH[2]}
Converting that into a new date might be trickier. If you have GNU date, though, you can use
output=$(date --date "$year-1-1 + $(($day - 1)) days" +"SNC_obs_%Y%m%d0000.png")
If you aren't using bash and are limited to POSIX-specified features, try the following to set year and day.
tmp=${input#ims}
tmp=${tmp%%_*}
year=${tmp%???}
day=${tmp#????}

Bash - File name change Date + 1

I have around 500 files that I need to rename with the date the report represents. The filenames are currently:
WUSR1453722998383.csv
WUSR1453723010659.csv
WUSR1453723023497.csv
And so on. The numbers in the filename have nothing to do with the date, so I cannot use the filename as a guide for what the file should be renamed to. The reports start from 02/12/2014 and there is a report for every day of the month up until yesterday (09/04/2016). Luckily as well the filename is sequential - so 04/12/2014 will have a higher number than 03/12/2014 which will have a higher number than 02/12/2014. This means the files are automatically listed in alphabetical order.
There is however a date in the first line of the CSV before the data:
As at Date,2014-12-02
Now I've checked that I have all the files already and I do, so what's the best way to rename there to the date? I can either set the starting date as 02/12/2014 and rename each file as a +1 date or the script can read the date on the first line of the file (As at Date,2014-12-02 for example) and use that date to rename the file.
I have no idea how to write either of the method above in bash, so if you could help out with this, that would be really appreciated.
In terms of file output, I was hoping for:
02-12-2014.csv
03-12-2014.csv
And so on
Is that the answer you need? Assume all the file are under current directory. Do some testings before you do the real operation. The condition is every date string at your cvs file is unique. There will be some files be overwritten otherwise.
#!/bin/bash
for f in *.csv
do
o=$(sed '1q' $f |awk -F"[,-]" '{print $NF"-"$(NF-1)"-"$(NF-2)".csv"}')
# should we backup the file?
# cp $f ${f}.bak
mv $f $o
done

Unique Linux filename, sortable by time

Previously I was using uuidgen to create unique filenames that I then need to iterate over by date/time via a bash script. I've since found that simply looping over said files via 'ls -l' will not suffice because evidently I can only trust the OS to keep timestamp resolution in seconds (nonoseconds is all zero when viewing files via stat on this particular filesystem and kernel)
So I then though maybe I could just use something like date +%s%N for my filename. This will print the seconds since 1970 followed by the current nanoseconds.
I'm possibly over-engineering this at this point, but these are files generated on high-usage enterprise systems so I don't really want to simply trust the nanosecond timestamp on the (admittedly very small) chance two files are generated in the same nanosecond and we get a collision.
I believe the uuidgen script has logic baked in to handle this occurrence so it's still guaranteed to be unique in that case (correct me if I'm wrong there... I read that someplace I think but the googles are failing me right now).
So... I'm considering something like
FILENAME=`date +%s`-`uuidgen -t`
echo $FILENAME
to ensure I create a unique filename that can then be iterated over with a simple 'ls' and who's name can be trusted to both be unique and sequential by time.
Any better ideas or flaws with this direction?
If you order your date format by year, month (zero padded), day (zero padded), hour (zero padded), minute (zero padded), then you can sort by time easily:
FILENAME=`date '+%Y-%m-%d-%H-%M'`-`uuidgen -t`
echo $FILENAME
or
FILENAME=`date '+%Y-%m-%d-%H-%M'`-`uuidgen -t | head -c 5`
echo $FILENAME
Which would give you:
2015-02-23-08-37-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
or
2015-02-23-08-37-xxxxx
# the same as above, but shorter unique string
You can choose other delimiters for the date/time besides - as you wish, as long as they're within the valid characters for Linux file name.
You will need %N for precision (nanoseconds):
filename=$(date +%s.%N)_$(uuidgen -t); echo $filename
1424699882.086602550_fb575f02-bb63-11e4-ac75-8ca982a9f0aa
BTW if you use %N and you're not using multiple threads, it should be unique enough.
You could take what TIAGO said about %N precision, and combine it with taskset
You can find some info here: http://manpages.ubuntu.com/manpages/hardy/man1/taskset.1.html
and then run your script
taskset --cpu-list 1 my_script
Never tested this, but, it should run your script only on the first core of your CPU. I'm thinking that if your script runs on your first CPU core, combined with date %N (nanoseconds) + uuidgen there's no way you can get duplicate filenames.

Resources