Appending Filenames
If you google how to append, say, current timestamp to the filename in Bash, almost every suggestion boils down to something really basic along the lines of mv $somefile $somefile_$(date +'Y%-%m-%d')
. Technically, this is correct and, yet, this is not what was needed.
Most filenames have extensions that visually identify the files’ type and purpose. If you append a date to the end of the filename, you will effectively remove the filename extension. This is impractical, annoying, and can break things, as illustrated below.
tail -1000 /var/log/messages > /tmp/testfile.log gzip /tmp/testfile.log mv /tmp/testfile.log.gz /tmp/testfile.log.gz_$(date +'%Y-%m-%d') gzip -d /tmp/testfile.log.gz_$(date +'%Y-%m-%d') gzip: /tmp/testfile.log.gz_2019-11-17: unknown suffix -- ignored
What I really wanted was a new filename looking something like this: /tmp/testfile_2019-11-17.log.gz
Let’s imagine we have a file called `unix_server_inventory.xlsx` and we want to make a copy of it with the latest modification date appended to the filename. We want to preserve the .xlsx
extension. But we also want the same command to work even if the filename has no extension. And here it is:
f=unix_server_inventory.xlsx /bin/cp -p "${f}" "${f%.*}_$(date -d @$(stat -c %Y "${f}") +'%Y-%m-%d')$([[ "${f}" = *.* ]] && echo ".${f##*.}" || echo '')" ls unix_server_inventory* unix_server_inventory.xlsx unix_server_inventory_2019-11-12.xlsx
Here’s a similar example but the filename now comes with full path and the copy is created in the original directory with the last modification timestamp appended.
f=/root/unix_server_inventory.xlsx /bin/cp -p "${f}" "$(dirname "${f}")/$(basename -- "${f%.*}")_$(date -d @$(stat -c %Y "${f}") +'%Y-%m-%d')$([[ "${f}" = *.* ]] && echo ".${f##*.}" || echo '')"
And another example of renaming multiple files, also by appending the last modification timestamp.
find ${source_path} -mindepth 1 -maxdepth 1 -type f -name "netapp_unix_clients*\.txt" -exec sh -c 'for f; do /bin/cp -p "${f}" "${target_path}/$(basename -- ${f%.*})_$(date -d @$(stat -c %Y ${f}) +'%Y-%m-%d')$([[ "${f}" = *.* ]] && echo ".${f##*.}" || echo '')"; done' sh {} +
Trying to remember the syntax of these commands is probably impractical. A better solution would be to write a small helper script. Perhaps something like this:
#!/bin/bash f="${@}" if [ -z "${f}" ] || [ ! -f "${f}" ]; then exit 1; fi /bin/cp -p "${f}" "$(dirname "${f}")/$(basename -- "${f%.*}")_$(date -d @$(stat -c %Y "${f}") +'%Y-%m-%d')$([[ "${f}" = *.* ]] && echo ".${f##*.}" || echo '')"
Save it as /var/adm/bin/cpr.sh
and then chmod 755 /var/adm/bin/cpr.sh && ln -s /var/adm/bin/cpr.sh /usr/bin/cpr
. Syntax would be very basic:
[root@ncc1711:~] # touch "/tmp/igor 1.txt" [root@ncc1711:~] # cpr /tmp/igor 1.txt [root@ncc1711:~] # ls -als /tmp | grep igor 0 -rw-r--r-- 1 root root 0 Nov 17 11:21 igor 1_2019-11-17.txt 0 -rw-r--r-- 1 root root 0 Nov 17 11:21 igor 1.txt