I have a directory where I store backups. The are in the format Complete Backup YYYY-MM-DD hh-mm-ss.tar.bz2 I have found out that you can feed a date into the date command using date --date="YY-MM-DD hh:mm:ss".

So how would I get a space separated list of dates. The dates should have run through a call of date so that they are formated.

I came up with this command that gives me a list (one entry per line) in the format of YYYY-MM-DD hh-mm-ss. So how would I format it correctly and do a date on every one of them and the seperate them with a space?

dir backups/ | grep '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\\ [0-9][0-9]-[0-9][0-9]-[0-9][0-9]\.tar\.bz2$' | sed 's/\\//g' | sed 's/\.tar\.bz2//g' | sed 's/Complete Backup //g'

Note: The output will be use in a select loop so every space belonging to a date should be escaped.

2 Answers 2


The following will reformat the dates:

dir -1 backups | awk '/Complete\\ Backup\\ .*\.tar\.bz2/ { gsub(/\\/, ""); sub(/Complete Backup /, ""); sub(/.tar.bz2/, ""); gsub(/-/, " "); print strftime("%c", mktime($0)); }'

And here's a way to get that into a select:

OIFS="$IFS"; IFS=$'\n'; set -- $(dir -1 backups | awk '/Complete\\ Backup\\ .*\.tar\.bz2/ { gsub(/\\/, ""); sub(/Complete Backup /, ""); sub(/.tar.bz2/, ""); gsub(/-/, " "); print strftime("%c", mktime($0)); }'); IFS="$OIFS"
select date in "$@"; do echo "$date"; done

Here's a version that sorts the dates:


set -- $(
    dir -1 backups |
    awk '/Complete\\ Backup\\ .*\.tar\.bz2/ \
            gsub(/\\/, "");
            sub(/Complete Backup /, "");
            sub(/.tar.bz2/, "");
            gsub(/-/, " ");
            VAL[NR] = mktime($0);

         END \
            for ( i = asort(VAL); i > 0; i-- )
                    print strftime("%a %b %d %T %Z %Y", VAL[i]);


select date in "$@"
    echo "$date"
  • It looks like that you forgot that dir escapes space as \ . At least I get no output or an error: awk: cmd. line:1: (FILENAME=- FNR=1) fatal: strftime: second argument less than 0 or too big for time_t
    – BrainStone
    Aug 29, 2013 at 0:19
  • Ah, apologies - ls is my weapon of choice I'll fix it.
    – ash
    Aug 29, 2013 at 0:28
  • is it possible to sort it so that the it's sortet descending by date? (Earliest first, latest last) And does this affect the parameters given to the script? Meaing would $1 still be the same before and after?
    – BrainStone
    Aug 29, 2013 at 0:38
  • 1
    Here's a short explanation. IFS changes how the shell splits values. OIFS is just saving IFS. set -- ... sets the shell positional parameters, applying IFS to the text that follows the --. The '$(...)` executes a command and replaces itself with the standard output of the command. The dir -1 backups output is piped into an awk script which, for all lines matching the regex Complete\\ Backup\\ .*\.tar\.bz2, it strips backslashes, then the "Complete Backup" text, then ".tar.bz2", and finally "-". Awk's mktime() takes the result (YYYY MM DD HH MM SS) and...
    – ash
    Aug 29, 2013 at 0:52
  • 1
    ... turns it into a time_t value (seconds since the EPOCH). Wheh, ok not short - but quick. In the sorted version, it puts that value into an associative array indexed by line number (line number is not really important). Then, the END block executes at the end of input to awk, and at that time, it prints the formatted date. Oops... forgot to sort.
    – ash
    Aug 29, 2013 at 0:54

Here you go:

dates=($(for i in backups/*.tar.bz2;do #Glob eliminates need to list all files
             date=${i/Complete Backup /} #Remove "Complete Backup "
             date=${date%%.*} #Remove ".tar.bz2"
             date=${date/ /,} #Substitue , for space
             echo $date #Echo the date for sed
         done|sed -e 's/\([0-9]\+\)-\([0-9]\+\)-\([0-9]\+\)$/\1:\2:\3/'|sort -r|xargs echo))
select date in ${dates[@]};do
    echo "$date"

One more thing: if you're using this for a select loop, how are you going to tell the different dates apart when they're space-separated? I mean you use space to separate the date from the time as well so this might be a source of confusion.


  • Added sorting of the dates from newest to oldest since your comments indicate that you need them sorted that way.
  • Added code to separate date and time by a comma so that select can tell a date and time pair from a new entry altogether.
  • Wrapped the whole in a select loop Stored the dates into an array which is then iterated over by a select loop to avoid having to re-parse the dates for each re-run of the loop.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .