Tagbash

Locally remount volumes from Docker to be used by local user using bindfs

#!/bin/bash
set -exou pipefail

# Location of the script (not the location from where it is executed from
THISDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

DOCKER_VOLUME_DIR=volumes  # This is the directory docker mounts to
LOCAL_DOCKER_VOLUME_DIR=localvolumes # This is the directory you want to locally mount to.
INSIDE_CONTAINER_USER=1000

# Bindfs is required
APP=bindfs; [ -x "`which ${APP}`" ] || sudo apt install ${APP}

# Create local directory to map volume to.
[ ! -d ${THISDIR}/${LOCAL_DOCKER_VOLUME_DIR} ] && mkdir -p ${THISDIR}${LOCAL_DOCKER_VOLUME_DIR}

# Unmount if already mounted
sudo umount ${THISDIR}/${LOCAL_DOCKER_VOLUME_DIR} || true

# Bet local users group
GROUP=`id -g -n $USER`

# Mount
sudo bindfs -u $USER -g "$GROUP" --create-for-user=${INSIDE_CONTAINER_USER} --create-for-group=${INSIDE_CONTAINER_USER} ${THISDIR}/${DOCKER_VOLUME_DIR} ${THISDIR}/${LOCAL_DOCKER_VOLUME_DIR}

Based on https://www.fullstaq.com/knowledge-hub/blogs/docker-and-the-host-filesystem-owner-matching-problem

Bash cheatsheet!

Just a collection of oneliners often use, but always forget 🙂 The following can be used from the terminal, or be used as a script.

#!/bin/bash
# ^^ Always start with a shebang!

# -e = immediately exit if any command has non-zero exit status
# -o pipefail = prevents masking of errors in a pipeline
# -u = error when using reference that has not been defined 
set -eou pipefail

# Check if directory is present before creating to avoid annoying warning.
[ ! -d /tmp/whatever ] && mkdir -p /tmp/whatever

# Check if file exists before performing operation on it.
[ -f file.txt ] && echo "blah" >> file.txt

# Check that script is NOT run as root
[[ $EUID -ne 0 ]] || {
    echo "[ERROR]     Do not run as root!"
    exit 1
}

# Check that script is run as root
[[ $EUID -ne 0 ]] && {
    echo "[ERROR]     This script must be run as root"
}

# Location of the script (not the location from where it is executed from
THISDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

# Grep, but do not match grep itself -> put first character of grep match in square brackets []. Suppose we want to see if blender is still running:
ps ax | grep [b]lender

# Kill application by name (when pkill is absent ;) ) Suppose we want to kill "my-awesome-app" 
ps ax | grep -i [m]y-awesome-app | awk '{ print $2 }'

# Install only if not installed.
APP=bindfs; [ -x "`which ${APP}`" ] || sudo apt install ${APP}

# Use default if first argument on command line is not set.
FIRST_ARG="${1:-some_default_var}"  

# Get the amount of CPUs on the device (-1, to use for parallel jobs)
cpus=$(($(nproc) -1))
# Or
cpus=$(($(grep -c "^processor" /proc/cpuinfo) - 1))

Replace variables from file using sed

Some configuration files are dependent on where the location of you location is. Therefore I mostly have variables in the configuration files, that I replace upon installation using sed.

As an example I have a systemd service file (example.service):

[Unit]
Description=My app

[Service]
WorkingDirectory={{WORKING_DIR}}
ExecStart=/usr/bin/python3 {{WORKING_DIR}}/app.sh
Restart=always

[Install]
WantedBy=multi-user.target

Then run the following on this file:

sed "s,{{WORKING_DIR}},/location/to/application/dir,g" example.service > /etc/systemd/system/example.service

Then the service file is installed and the variables are replaced with the path to your liking.

Useful one-liners

https://gist.github.com/johnnypea/b0cd77e5734d65691fa21d93274b305b

Get status of git repositories in directory

I have a development directory (~/dev) which houses all of my git repositories.
Recently I bought another laptop, but to make sure I pushed all my local development I check the status of the git repositories with the following bash script:

#!/bin/bash

gitrepos=`find . -type d -name ".git" -prune -print | xargs -I {} dirname {}`

for repo in $gitrepos; do
  pushd $PWD > /dev/null
  cd $repo
  # echo $PWD
  if git diff-index --quiet HEAD --; then
    echo -e "UP TO DATE\t - $repo"
  else
    echo -e "CHANGES\t\t - $repo"
  fi
  popd > /dev/null
done

Place the code above in a file e.g. repostatus.sh and make it executable: chmod +x repostatus.sh.

Programatically switch tabs in a browser

So, if been looking to programatically switch tabs of a browser in kiosk mode. This is a quick way to do exactly that.

So first you have to install xdotool. I did this on a Ubuntu machine using apt:

$ sudo apt install xdotool

Then put the following in a file and make that executable (chmod +x yourscript.sh):

#!/bin/bash

BROWSER="Brave"
direction=$1

action="Ctrl+Tab"
if [[ "${direction}" == "left" ]]; then
  action="Ctrl+Shift+Tab"
fi

xdotool windowactivate --sync $(xdotool search --name ${BROWSER} | tail -n 1) && xdotool key ${action}

Execute it with an argument “left” or “right” (right = default). On execution it will locate your browser (“Brave”), then it emulates a shortcut to go to the next or previous tab.

The goals is to fire this script once a button has been pressed on a Kiosk such that the user can choose which tab to show.

Completely wipe Bash history

Clearing out your bash history can be quite a hassle as it keeps a copy in the memory that will be flushed at the moment you log out. There is a workaround:

cat /dev/null > ~/.bash_history && history -c && exit

After this command the history is wiped.
I use this when creating binary copies of the filesystem when I do not want to include any history (Create bitwise copy of EMMC/SD/HDD/SDD over the network (backup using ssh pipe)).

Source: https://askubuntu.com/a/192001

Create bitwise copy of EMMC/SD/HDD/SDD over the network (backup using ssh pipe)

It can be convenient to make a bitwise copy. For example to place the contents of 1 embedded board (i.e. Beaglebone) to another embedded board.

If the device to copy is also the storage device that holds the OS, then boot from another device, for example a “Try Ubuntu” usb drive.

We stream the data over the network, because the devices themselves mostly have no space to place the image somewhere on the that device.

Assumption is that you have a working ssh server on the device you want to copy to.

The perform the following:

  1. Find the correct device to make a copy from. So the whole device, not the partition.
    In my case it is “/dev/mmcblk0” so without the partition indicator -> “p1”.
  2. Find the ip adress of the device to copy to (or use hostname)

To create an image:

> sudo cat /dev/mmcblk0 | ssh <user>@<ip-adress> "gzip ~/image.gz"

After the operation is done you have a bitwise copy gzipped on your <ip-address> machine in the home directory of the <user>

To deploy an earlier created image back to the device, from the device to deploy to (Make sure you booted from another device than we are copying to):

> ssh <user>@<ip-address> "gzip -dc ~/image.gz" | dd of=/dev/mmcblk0 status=progress

Wipe bash history!

If you were ever to create an image of your OS for example, but do not want to include your history.

It also wipes the history still in the memory.

cat /dev/null > ~/.bash_history && history -c && exit

Also, if you don’t even want that your command ends up in your bash history in the first place, add a space at the start of you command and it will not be in your bash history!

> echo "inhistory" > blaa
>   echo "notinhistory" > blaa  #notice the space

The “notinhistory” is not in the history file:

> history | tail -n1
10438  echo "inhistory" > blaa

Bash script template

Whenever writing a script you might want to enable some options depending on what you provide on the CLI.

I’ve created a bash script template to getting started quick with a bash script. You can specify full options or the short ones with arguments or without.

#!/bin/bash
# Version 2.0
# Script template

set -eou pipefail

DO_OPT_A=false
DO_OPT_B=false

# directory of the script, can be useful for locating files which are next to the script.
THISDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

function main() {
  check_root

  do_parse_opts $@

  [[ ${DO_OPT_A}   = true ]] && check_opt_a_prerequisites
  [[ ${DO_OPT_B}   = true ]] && check_opt_b_prerequisites

  print_info "Checks OK, you have 2s to abort now!"
  sleep 2
  echo ""

  [[ ${DO_OPT_A} = true ]] && {
    do_opt_a_function
  }

  [[ ${DO_OPT_B} = true ]] && {
    do_opt_b_function
  }
}

function show_help() {
  echo "Scripting template :)"

  echo "Usage:"
  echo "    $0 [-a/--option_a] [-b/--option_b <arg>]"

  echo "        *  [-h/--help]      Print this help"
  echo "        *  [-a/--option_a]  Perform option A"
  echo "        *  [-b/--option_b <arg>]  Perform option B with argument"
  echo ""
  exit 1
}

function do_parse_opts() {
  # convert long options to shorts
  for arg in "$@"; do
    shift
    case "$arg" in
        "--help")       set -- "$@" "-h" ;;
        "--option_a")   set -- "$@" "-a" ;;
        "--option_b")   set -- "$@" "-b" ;;
        *)              set -- "$@" "$arg"
    esac
  done

  OPTIND=1 # Reset in case getopts has been used previously in the shell.
  while getopts "hab:" opt; do
      case "$opt" in
      h)
          show_help
          exit 0
          ;;
      a)  DO_OPT_A=true
          ;;
      b)  DO_OPT_B=true
          BARG=$OPTARG
          ;;
      esac
  done

  shift $((OPTIND-1))

  [ "${1:-}" = "--" ] && shift

  print_info "DO_OPT_A    = $DO_OPT_A"
  print_info "DO_OPT_B    = $DO_OPT_B"

  [[ ${DO_OPT_A} = false ]] && [[ ${DO_OPT_B} = false ]] && {
    print_info "Hey! Your provided no options, this might help:"
    echo ""
    show_help
  }

  echo ""
}

function check_root() {
    [[ $EUID -ne 0 ]] && {
        echo "[ERROR]     This script must be run as root"
        show_help
    }
}

function check_opt_a_prerequisites() {
    print_info "Checking option A prerequisites"
    sleep 1
    print_ok
}

function check_opt_b_prerequisites() {
    print_info "Checking option B prerequisites"
    sleep 1
    print_ok
}


function do_opt_a_function() {
    print_info "Performing A"
    sleep 1
    print_ok
}


function do_opt_b_function() {
    print_info "Performing B, with arg: ${BARG}"
    sleep 1
    print_ok
}


function print_ok() {
  echo "[OK]"
}

function print_info() {
  echo "[INFO]      $1..."
}

function print_error() {
  echo "[ERROR]     $1"
  exit 1
}


main $@

print_info "All done!"
echo "[OK]"

© 2025 Roholt

Thema door Anders NorénOmhoog ↑