Rename file from Day of the Year to YYMMDD0000 - bash

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#????}

Related

Linux shell - parse date in odd formats

Is there any way to use standard tools (not programming scripts) to parse the date in custom, odd format?
I've got a start script (bash) that should handle the output of the program, that contains dates with very odd formatting (like Jan, 4, 2021, 1:20:30 PM - which would be a pattern like "MMM, d, yyyy, h:mm:ss a".
It would be possible to extract the tokens with sed or awk, but processing them is a nightmare, especially month shortcuts (they are in the same language like system, but that language can be installation-specific) or hours (need to check AM/PM token and add 12 if it's PM).
'date' apparently doesn't support that, but maybe some shell extension or toolkit package? Or I'm out of luck and I need to parse this crappy format token by token with sed/cut/awk?
This what I've tried was to do touch -d "Date" after removing the commas (so that I can compare dates with [[ file1 -ot file2 ]], but the problem is, that touch has ignored the TIME part, and ls -lh has shown, that the year was set in place of time, and the result of the comparison was therefore invalid.
Convert date with GNU date and bash:
d="Jan, 4, 2021, 1:20:30 PM"
IFS=',:' read mon day year hour min sec a <<<"$d"
date -d "$mon $day $year $hour:$min:$sec $a" '+%Y-%m-%d %H:%M:%S'
Output:
2021-01-04 13:20:30

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.

Get today's date minus one Year in Unix (AIX)

I need to find today's date and then subtract a year and format that date into the YYYY-MM-dd format.
I am able to accomplish this with a script I wrote, but apparently it is only compatible with bash. I need it to be compatible with AIX.
lastYear=`date +'%Y-%m-%d' -d 'last year'`
searchDate="$lastYear 00.00.00";
echo "Retrieving data start from $searchDate"
myquery="myquery >= '$searchDate'"
The result when run on an AIX machine is that it only passes the "00:00:00" part of the $searchDate, the date does not prefix before the time as I hoped. What is the safest way to write this for the most compatibility across Linux/Unix variations?
Thank you!
Why make it so complicated?
#!/bin/ksh
typeset -i year=$( date +%Y )
(( year -= 1 ))
typeset rest=$( date +%m-%d )
echo "${year}-${rest}"
This should work in any shell. If you use sh replace the
$( ... )
with back tics
` ... `
But for bash and ksh I use $( ... ) -- just personal preference.
Checkout Updated Section Below
Original Answer
Try this. It uses the -v flag to display the result of adjusting the current date by negative one year -1y
searchDate=$(date -v-1y +'%Y-%m-%d')
echo "Retrieving data start from $searchDate"
myquery="myquery >= '$searchDate'"
Here is the output:
Retrieving data start from 2017-06-21
Note: I did try to run the lines you provided above in a script file with a bash shebang, but ran into an illegal time format error and the output was 00:00:00. The script I provided above runs cleanly on my unix system.
Hope this helps. Good luck!
Updated Section
Visit ShellCheck.net
It's a nice resource for testing code compatibility between sh, bash, dash, and ksh(AIX's default) shells.
Identifying the Actual Issue
When I entered your code, it clearly identified syntax that is considered legacy and suggested how to fix it, and gave this link with an example and a great explanation. Here's the output:
lastYear=`date +'%Y-%m-%d' -d 'last year'`
^__Use $(..) instead of legacy `..`.
So, it looks like you might be able to use the code you wrote, by making one small change:
lastYear=$(date +'%Y-%m-%d' -d 'last year')
Note: This question already has an accepted answer, but I wanted to share this resource, because it may help others trouble-shoot shell compatibility issues like this in the future.

Getting the name of the folder and comparing to integer in 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.

Cshell Script date issue

Is there a way to add date in the name of the file... we can add current date in this manner date '+%Y%m%d' but i want to add "filename_date_1-2-2011_thru_31-2-2011.txt" Is it possible to do that??????????
If you have a sufficiently advanced version of the date command and you know a Unix timestamp for the start and end dates, then you can use:
(MacOS X) date -r 1234567890 "+%d-%m-%Y" to obtain 13-02-2009.
(GNU) date -d 2/13/2009 "+%d-%m-%Y" to obtain 13-02-2009 again.
If you don't want the leading zeroes on the day of month, then you need to use '%e` instead of '%d' on Linux (but that puts a space in place of the zero). It is not clear that there's a format specifier for day-of-month without a leading zero on MacOS X; nor is it clear that there's a way to format month of year as a single-digit number for January to September on either platform.
You get the format into your C shell script using back-ticks around the date commands.
Consider reading Csh Programming Considered Harmful and heeding its advice.

Resources