1

I have a list I want to change from a script. I want to move top entry to bottom so I get a rotating list each time the script is run. I also want to append date to the line that got moved to bottom. from this. The top folder will be used to store old backups too using rclone.

old1
old2
old3

to this

old2
old3
old1 date time

I found a code I tried to use, but it wont move the top entry, just copy it to bottom so I get an output like this

old1
old2
old3
old1 date time
old1 date time

The code I tried # Rotate the BACKUPLIST-file, deleting the top entry and adding a new entry at the bottom
OLDEST=$(head -1 $BACKUPLIST | sed 's/ .*//') # The oldest, extra backup-version COUNT=$(cat $BACKUPLIST | wc -l) # Number of files in list
((COUNT=$COUNT-1)) tail -$COUNT $BACKUPLIST > $BACKUPLIST.tmp echo $OLDEST $(date) >> $BACKUPLIST.tmp # Add a new line to the bottom, including today's date

1
  • You're using sed 's/ .*//' to remove an existing date from the first line, right?
    – Freddy
    Commented Jul 25, 2019 at 21:48

4 Answers 4

2

It's a little tricky to get the escaping correct in the date format string, but given

$ cat file
old1
old2
old3

then

$ cat << 'EOF' | ed -s file
1m$
r !date +\ \%x\ \%X
.-1,.j
,p
EOF
old2
old3
old1 2019-07-25 05:42:32 PM

or (as a one-liner)

printf '%s\n' '1m$' 'r !date +\ \%x\ \%X' '.-1,.j' ',p' | ed -s file

To edit the file in place, replace p (print) by wq (write-quit). You can replace %x and %X with other format specifiers of your choice of course.

4
  • 1
    heh, I was just working on an ed version. I came up with printf '%s\n' '1,1m$' "s/$/ $(date "+%F %T")/" wq | ed file Commented Jul 25, 2019 at 21:24
  • 1
    @glennjackman hmm yes that might have been simpler Commented Jul 25, 2019 at 21:33
  • 1
    I find heredocs are more readable for ed commands. Commented Jul 25, 2019 at 21:34
  • 1
    @prophetse7en, since ed is an actual editor, this will be more efficient than reading and re-writing the whole file. Commented Jul 25, 2019 at 21:35
1
$ date +"$(head -n 1 file) %F %T" >>file; sed -i 1d file
$ cat file
old2
old3
old1 2019-07-25 23:39:51
$ date +"$(head -n 1 file) %F %T" >>file; sed -i 1d file
$ cat file
old3
old1 2019-07-25 23:47:10
old2 2019-07-25 23:47:22

This inserts the first line of file as a string into the output format of date. The %F is a shorthand for %Y-%m-%d and %T is a shorthand for %H:%M:%S in most date implementations.

The output of date is then appended to the end of file.

After appending the new data, sed is used to delete the old first line (using an in-place edit). Some sed implementation has to be invoked as sed -i '' 1d file (see How can I achieve portability with sed -i (in-place editing)?).


The fourth run of the commands above would yield

$ date +"$(head -n 1 file) %F %T" >>file; sed -i 1d file
$ cat file
old2 2019-07-25 23:47:22
old3 2019-07-25 23:51:22
old1 2019-07-25 23:47:10 2019-07-25 23:51:24

If this is not wanted, use something like

awk '{ print $1; exit }'

in place of head -n 1. This would pick out the first whitespace-delimited column on the first line, but not the full first line with the old date and time.

0

You can do this quickly in bash:

mapfile -t lines < file
printf "%s\n" "${lines[@]:1}" "${lines[0]} $(date "+%F %T")" > file

Putting that into a function:

rotate_file() {
    [[ -w "$1" ]] || return 1
    local -a lines
    mapfile -t lines < "$1"
    printf "%s\n" "${lines[@]:1}" "${lines[0]} $(date "+%F %T")" > "$1"
}

A demo:

$ cat file
1
2
3
$ rotate_file file
$ cat file
2
3
1 2019-07-25 17:16:51
$ rotate_file file
$ cat file
3
1 2019-07-25 17:16:51
2 2019-07-25 17:16:57

This slurps the whole file into memory. If the file is large, this can be slow.

0
$ hd="$(head -1 file)"; tail +2 file; printf '%s %s\n' "$hd" "$(date)"
old2
old3
old1 Thu, Jul 25, 2019  4:27:15 PM

$ hd="$(head -1 file)"; { tail +2 file; printf '%s %s\n' "$hd" "$(date)"; } > tmp && mv tmp file; cat file
old2
old3
old1 Thu, Jul 25, 2019  4:28:44 PM

$ hd="$(head -1 file)"; { tail +2 file; printf '%s %s\n' "$hd" "$(date)"; } > tmp && mv tmp file; cat file
old3
old1 Thu, Jul 25, 2019  4:28:44 PM
old2 Thu, Jul 25, 2019  4:28:46 PM

$ hd="$(head -1 file)"; { tail +2 file; printf '%s %s\n' "$hd" "$(date)"; } > tmp && mv tmp file; cat file
old1 Thu, Jul 25, 2019  4:28:44 PM
old2 Thu, Jul 25, 2019  4:28:46 PM
old3 Thu, Jul 25, 2019  4:28:48 PM
1
  • 1
    @glennjackman fair enough, I just added the code to do it. Should be pretty self-explanatory.
    – Ed Morton
    Commented Jul 25, 2019 at 21:32

You must log in to answer this question.

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