Categories
SysOps

How to perform different operations depending on the shell script name

This technique is widespread. To be honest, it is more common than I initially thought, so I will show you how to create a single shell script that will display, create or destroy a temporary file system depending on the name used to execute it.

Standard utilities

Look at the standard utilities, as many of these behave differently depending on the used executable name.

$ find {/bin,/sbin,/usr/bin,/usr/sbin} -type l -not -lname "*alternatives*" -and -not -lname "/*" -exec stat --format="%N" {} \; | sort
'/bin/bzcmp' -> 'bzdiff'
'/bin/bzegrep' -> 'bzgrep'
'/bin/bzfgrep' -> 'bzgrep'
'/bin/bzless' -> 'bzmore'
'/bin/dnsdomainname' -> 'hostname'
'/bin/domainname' -> 'hostname'
'/bin/lessfile' -> 'lesspipe'
'/bin/nisdomainname' -> 'hostname'
'/bin/rbash' -> 'bash'
'/bin/sh' -> 'dash'
'/bin/sh.distrib' -> 'dash'
'/bin/ypdomainname' -> 'hostname'
'/sbin/dmstats' -> 'dmsetup'
'/sbin/e2label' -> 'tune2fs'
'/sbin/fsck.ext2' -> 'e2fsck'
'/sbin/fsck.ext3' -> 'e2fsck'
'/sbin/fsck.ext4' -> 'e2fsck'
'/sbin/getty' -> 'agetty'
'/sbin/ifdown' -> 'ifup'
'/sbin/ifquery' -> 'ifup'
'/sbin/mkfs.ext2' -> 'mke2fs'
'/sbin/mkfs.ext3' -> 'mke2fs'
'/sbin/mkfs.ext4' -> 'mke2fs'
'/usr/bin/atq' -> 'at'
'/usr/bin/atrm' -> 'at'
'/usr/bin/captoinfo' -> 'tic'
'/usr/bin/compose' -> 'run-mailcap'
'/usr/bin/ctstat' -> 'lnstat'
'/usr/bin/edit' -> 'run-mailcap'
'/usr/bin/i386' -> 'setarch'
'/usr/bin/infotocap' -> 'tic'
'/usr/bin/lastb' -> 'last'
'/usr/bin/linux32' -> 'setarch'
'/usr/bin/linux64' -> 'setarch'
'/usr/bin/mailq' -> '../sbin/exim4'
'/usr/bin/md5sum.textutils' -> 'md5sum'
'/usr/bin/newaliases' -> '../sbin/exim4'
'/usr/bin/pkill' -> 'pgrep'
'/usr/bin/print' -> 'run-mailcap'
'/usr/bin/pstree.x11' -> 'pstree'
'/usr/bin/reset' -> 'tset'
'/usr/bin/rtstat' -> 'lnstat'
'/usr/bin/see' -> 'run-mailcap'
'/usr/bin/sg' -> 'newgrp'
'/usr/bin/slogin' -> 'ssh'
'/usr/bin/snice' -> 'skill'
'/usr/bin/sudoedit' -> 'sudo'
'/usr/bin/unxz' -> 'xz'
'/usr/bin/x86_64' -> 'setarch'
'/usr/bin/xzcat' -> 'xz'
'/usr/bin/xzcmp' -> 'xzdiff'
'/usr/bin/xzegrep' -> 'xzgrep'
'/usr/bin/xzfgrep' -> 'xzgrep'
'/usr/sbin/addgroup' -> 'adduser'
'/usr/sbin/cpgr' -> 'cppw'
'/usr/sbin/delgroup' -> 'deluser'
'/usr/sbin/exim' -> 'exim4'
'/usr/sbin/rmail' -> 'exim4'
'/usr/sbin/rsmtp' -> 'exim4'
'/usr/sbin/runq' -> 'exim4'
'/usr/sbin/sendmail' -> 'exim4'
'/usr/sbin/vigr' -> 'vipw'

Shell script

This is a shell script that will change its behavior depending on the name it was called. Notice that the case statement is using script basename to execute different actions.

#!/bin/bash
# Perform different operation depending on the shell script name

# shell script name and real location
shell_script_name=$(basename $0)
real_shell_script_location=$(readlink -f $0)

# usage
usage() {
  echo "Usage:"
  echo " tmpfs-info"
  echo "   display information about mounted tmpfs file systems"
  echo " tmpfs-create location size"
  echo "   create tmpfs file system using provided location and size"
  echo " tmpfs-destroy location"
  echo "   destroy tmpfs file system at given location"
}

# display information
tmpfs-info() {
  mount -t tmpfs
}

# unmount tmpfs filesystem
tmpfs-destroy() {
  if [ -n "$1" ]; then
    location=$(readlink -f $1)
    mountpoint $location >/dev/null
    if [ "$?" -eq "0" ]; then
      fs=$(mount -t tmpfs | awk '$3 == "'$location'" {print $1}')   
      if [ "$fs" == "tmpfs" ]; then
        umount $location
      else
        echo "error: mountpoint is not tmpfs"
      fi
    else
      echo "error: provided location is not a mountpoint"
    fi
  else
    echo "error: missing mountpoint"
  fi      
}

# create tmpfs filesystem
tmpfs-create() {
  if [ -n "$1" ] && [ -n "$2" ]; then
    location=$(readlink -f $1)
    mountpoint $location >/dev/null
    if [ "$?" -eq "1" ]; then
      mount -t tmpfs -o size="$2" tmpfs "$location"
    else
      echo "error: provided location is already a mountpoint"
    fi
  else
    echo "error: missing mountpoint or size"
  fi      
}

# display shell script name and location
echo "Executed command $shell_script_name using $real_shell_script_location shell script"

# execute particular function depending on the shell script name
case "$shell_script_name" in
  "tmpfs-info")
    tmpfs-info
    ;;
  "tmpfs-create")
    tmpfs-create "$1" "$2"
    ;;
  "tmpfs-destroy")
    tmpfs-destroy "$1"
    ;;
  *)
    usage
    ;;
esac

Store the above-mentioned shell script as tmpfs.sh in /usr/bin directory.

Ensure that the executable bit is set.

$ sudo chmod +x /usr/bin/tmpfs.sh

Create symbolic links equivalent to the actions defined inside case statement.

$ sudo ln -s /usr/bin/tmpfs.sh /usr/bin/tmpfs-create
$ sudo ln -s /usr/bin/tmpfs.sh /usr/bin/tmpfs-destroy
$ sudo ln -s /usr/bin/tmpfs.sh /usr/bin/tmpfs-info

Usage

Display usage information.

$ tmpfs.sh
Executed command tmpfs.sh using /usr/bin/tmpfs.sh shell script
Usage:
 tmpfs-info
   display information about mounted tmpfs file systems
 tmpfs-create location size
   create tmpfs file system using provided location and size
 tmpfs-destroy location
   destroy tmpfs file system at given location

List mounted tmpfs file systems.

$ tmpfs-info 
Executed command tmpfs-info using /usr/bin/tmpfs.sh shell script
none on /dev type tmpfs (rw,nodev,relatime,size=492k,mode=755,uid=100000,gid=100000)
tmpfs on /dev/lxd type tmpfs (rw,relatime,size=100k,mode=755)
tmpfs on /dev/.lxd-mounts type tmpfs (rw,relatime,size=100k,mode=711)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,uid=100000,gid=100000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755,uid=100000,gid=100000)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k,uid=100000,gid=100000)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755,uid=100000,gid=100000)
tmpfs on /var/www/tmpfs type tmpfs (rw,nosuid,nodev,noexec,relatime,size=131072k,uid=100000,gid=100000)

Create tmpfs file system.

$ mkdir tmpfs_test
$ sudo tmpfs-create tmpfs_test 128M

List mounted tmpfs file systems to check out a new one.

$ tmpfs-info 
Executed command tmpfs-info using /usr/bin/tmpfs.sh shell script
none on /dev type tmpfs (rw,nodev,relatime,size=492k,mode=755,uid=100000,gid=100000)
tmpfs on /dev/lxd type tmpfs (rw,relatime,size=100k,mode=755)
tmpfs on /dev/.lxd-mounts type tmpfs (rw,relatime,size=100k,mode=711)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,uid=100000,gid=100000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755,uid=100000,gid=100000)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k,uid=100000,gid=100000)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755,uid=100000,gid=100000)
tmpfs on /var/www/tmpfs type tmpfs (rw,nosuid,nodev,noexec,relatime,size=131072k,uid=100000,gid=100000)
tmpfs on /root/tmpfs_test type tmpfs (rw,nodev,relatime,size=131072k,uid=100000,gid=100000)

Destroy previously created tmpfs file system.

$ sudo tmpfs-destroy tmpfs_test

List mounted tmpfs file systems to verify that it was removed.

$ tmpfs-info
Executed command tmpfs-info using /usr/bin/tmpfs.sh shell script
none on /dev type tmpfs (rw,nodev,relatime,size=492k,mode=755,uid=100000,gid=100000)
tmpfs on /dev/lxd type tmpfs (rw,relatime,size=100k,mode=755)
tmpfs on /dev/.lxd-mounts type tmpfs (rw,relatime,size=100k,mode=711)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,uid=100000,gid=100000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755,uid=100000,gid=100000)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k,uid=100000,gid=100000)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755,uid=100000,gid=100000)
tmpfs on /var/www/tmpfs type tmpfs (rw,nosuid,nodev,noexec,relatime,size=131072k,uid=100000,gid=100000)