Networking

Unix and Linux network configuration. Multiple network interfaces. Bridged NICs. High-availability network configurations.

Applications

Reviews of latest Unix and Linux software. Helpful tips for application support admins. Automating application support.

Data

Disk partitioning, filesystems, directories, and files. Volume management, logical volumes, HA filesystems. Backups and disaster recovery.

Monitoring

Distributed server monitoring. Server performance and capacity planning. Monitoring applications, network status and user activity.

Commands & Shells

Cool Unix shell commands and options. Command-line tools and application. Things every Unix sysadmin needs to know.

Home » Commands & Shells, Featured, Files

Appending Filenames

Submitted by on December 22, 2019 – 9:51 pm

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

 

 

Print Friendly, PDF & Email

Leave a Reply