2

I have a utility that outputs the software expiration date into a text file called expiration. The file has one line and it is below:

node_software_expiration_date Sat Jul 6 23:59:59 2025

I'd like to replace the text in the file to read:

node_software_expiration_date 20250706

I'm using sed to replace the current text. I can't edit the utility. Open to other options.

I'm running this in cron:

./export_expiration && sed -e 's/Software Expiration/node_software_expiration_date /' > expiration

DizzyNYC
  • 21
  • 4
  • 2
    I can't think of any straightforward way to do this with `sed`. – Barmar Jun 28 '22 at 20:47
  • 1
    It would improve the question title quite a great deal if it described the _from_ syntax, not just the _to_. Converting from `mm-dd-yyyy` to `yyyy/mm/dd`, f/e, is trivial. – Charles Duffy Jun 28 '22 at 20:49
  • It's beyond the capabilities of `sed` and probably even `awk`. I think you're into script/app code territory - try python? – Bohemian Jun 28 '22 at 20:49
  • @Bohemian this would be trivial in awk. – Ed Morton Jun 28 '22 at 20:56
  • @ed I wouldn't call that trivial. – Bohemian Jun 28 '22 at 21:04
  • 1
    `date --date=$(./export_expiration | sed 's/Software Expiration//') +%Y%m%d` or something similar should do the trick. You just need to separate the date from whatever other text it appears in and `date --date` can parse it. – Chris Dodd Jun 28 '22 at 21:04
  • @ChrisDodd looks promising. post an answer – Bohemian Jun 28 '22 at 21:05
  • @Bohemian really? it's the common, idiomatic approach for mapping 3 letter month names to numbers and then a printf to pad with zeros. – Ed Morton Jun 28 '22 at 21:11
  • When you say "using sed" in the title -- do you _really_ mean "using sed", as in any answer using awk, or native bash, or anything not sed would be rejected? (If you just meant "using UNIX tools", _say that_ instead). – Charles Duffy Jun 28 '22 at 21:47

6 Answers6

4

You can use date --date=STRING to parse pretty much any free-form date string (it accepts many different syntaxes, so is pretty robust), and then +FMT to output whatever format you want. The main difficultly with your example is replacing the file in place. Something like:

read prefix date < expiration
echo $prefix $(date --date="$date" +%Y%m%d) > expiration

should do the trick in a shell script. Note that if the input date string includes a time close to midnight in some other timezone, this may end up adjusting the day by one, which might actually be what you want.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • It's likely that by using all upper case for your variable names you'll clash with some environment variables, especially `PREFIX`. That's why you should never use all upper case for non-environment variables see [correct-bash-and-shell-script-variable-capitalization](https://stackoverflow.com/questions/673055/correct-bash-and-shell-script-variable-capitalization). Also see https://mywiki.wooledge.org/Quotes - quotes are something to remove when you need to, not something to add when you need to. You're also missing the `-r` that should be present on all `read`s by default. – Ed Morton Jun 28 '22 at 21:47
2

Using any awk in any shell on every Unix box:

$ awk '{printf "%s %04d%02d%02d\n", $1, $6, (index("JanFebMarAprMayJunJulAugSepOctNovDec",$3)+2)/3, $4}' file
node_software_expiration_date 20250706
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

Using GNU sed

$ sed -i "s/\([^ ]* \)\(.*\)/echo \1\$(date -d '\2' +'%Y%m%d')/e" input_file
$ cat input_file
node_software_expiration_date 20250706
HatLess
  • 10,622
  • 5
  • 14
  • 32
1

This might work for you (GNU sed):

sed -E 's/$/\nJan01Feb02Mar03Apr04May05Jun06Jul07Aug08Sep09Oct10Nov11Dec12/
        s/ (. ..:..:.. )/ 0\1/
        s/... (...) (..) ..:..:.. (....)\n.*\1(..).*/\3\4\2/' file

Append a lookup table.

Cater for the first nine days of a month.

Pattern match, forming the result in the desired format.

potong
  • 55,640
  • 6
  • 51
  • 83
0
$ awk '{n=$1; $1=""; printf "%s ",n; print |"date -d \"" $0 "\" +%Y%m%d"} file
node_software_expiration_date 20250706
ufopilot
  • 3,269
  • 2
  • 10
  • 12
0

I suggest following simple if somewhat long GNU sed solution, let file.txt content be node_software_expiration_date Sat Jul 6 23:59:59 2025 then

sed -e 's/ \([0-9]\) / 0\1 /g' -e 's/\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\)$/\5 \2 \3/' -e 's/ Jan /01/' -e 's/ Feb /02/' -e 's/ Mar /03/' -e 's/ Apr /04/' -e 's/ May /05/' -e 's/ Jun /06/' -e 's/ Jul /07/' -e 's/ Aug /08/' -e 's/ Sep /09/' -e 's/ Oct /10/' -e 's/ Nov /11/' -e 's/ Dec /12/' file.txt

gives output

node_software_expiration_date 20250706

Explanation: firstly pad single digit (digit surrounded with spaces) using 0 to width of 2. Then extract and change order of fields to that of desired format: that is year, month, day. Finally replace callsign of month and surrounding spaces with zero-padded number.

(tested in GNU sed 4.2.2)

Daweo
  • 31,313
  • 3
  • 12
  • 25