I've written some useful shell scripts during my time with Linux (which is coming up on 20 years now). I'm posting them here as a) a reminder to myself and b) because they might be useful for other people. In contrast to Stupid ZSH tricks, these are written in Bash to work more universally.

Nixify

Just set up the directory to use a shell.nix, and edit it in Emacs.

  #!/bin/bash
  
  echo "use nix" > .envrc
  direnv allow
  emacsclient shell.nix

PDFshrink

Reduce the size of PDFs via Ghostscript. Adapted from Stackoverflow and extended with some safety checks. Necessary, since remembering the necessary Ghostscript invocations is impossible. Automatically uses the input file with '-small' appended as the output file, if none has been provided.

  #!/bin/bash
  set -euo pipefail
  RESOLUTION="ebook"
  OVERWRITE="0"
  while getopts "r:ho" OPTION; do
      case $OPTION in
          r)
              RESOLUTION="$OPTARG"
              ;;
          o)
              OVERWRITE=1
              ;;
          h)
              cat <<EOF
  $0 [-r <resolution] <input file> <output file>
  
  -r: Choose resolution. Available:
      screen (72 dpi)
      ebook (150 dpi) [default]
      prepress (300 dpi)
      printer (300 dpi, optimized)
      default (unknown)
  -o: Overwrite output file (be careful)
  EOF
              exit 1
              ;;
          ,*)
              echo "Unknown argument $OPTION"
              exit 1
              ;;
      esac
  done
  
  shift "$((OPTIND-1))"
  
  INPUT="${1:?Provide an input file.}"
  OUTPUT="${2:-${INPUT%%.pdf}-small.pdf}"
  
  if [[ ! -r $INPUT ]]; then
      echo "Can not read input file $INPUT"
      exit 1
  fi
  
  if [[ -f $OUTPUT && $OVERWRITE == 0 ]]; then
      echo "Won't overwrite output file $OUTPUT"
      exit 1
  fi
  
  gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/"$RESOLUTION" -dNOPAUSE -dQUIET -dBATCH -sOutputFile="$OUTPUT" "$INPUT"

Resize image to size

I've found this very useful when sending job applications or similar. It allows you to resize an image to a specific size. It does this by using binary search to find the rescaling factor that best matches the required size to within a certain fuzz factor (one percent, in my version).

I'm actually kinda proud of this.

  #!/bin/bash
  set -euo pipefail
  
  if [[ $# -ne 2 ]]; then
      echo "Usage: $0 <file size limit in kilobytes> <imagefile>";
      exit;
  fi;
  UPPER=1.0
  LOWER=0.0
  CENTER=0.5
  FUZZ=0.01 			# One percent.
  
  originalsize=$(stat -c '%s' "$2")
  wantsize=$(($1 * 1024))
  
  if [[ "$originalsize" -le "$wantsize" ]]; then
      echo "Image already has smaller or correct size. Quitting.";
      exit;
  fi;
  TEMPFILE=$(mktemp)
  while [[ $(echo "$UPPER - $LOWER > $FUZZ" | bc -l) -eq 1 ]]; do
      CENTER=0$(echo "scale=5; $LOWER + (($UPPER - $LOWER) / 2)" | bc -l)
      convert "$2" -resize "$(echo "$CENTER * 100" | bc -l)%"  "$TEMPFILE"
      newsize=$(stat -c '%s' "$TEMPFILE")
      if [[ $newsize -lt $wantsize ]]; then
          LOWER=$CENTER; 
      else
          UPPER=$CENTER;
      fi;
  done;
  mv "$TEMPFILE" "${2%.*}"-resized."${2##*.}"

"Presentation mode"

When watching presentations or participating in Zoom calls, it often happens that my screensaver/monitor energy saving activates, because I'm not doing any typing. Additionally, I don't want my notifications to be shown while I'm sharing my screen. To do all this, I've written a shell script that turns of X11 power saving, pauses dunst notifications and inhibits systemd's autosuspend via systemd-inhibit. It's turned out very useful, and I've even added a tray icon via yad. Clicking it ends the presentation mode.

  #!/bin/bash
  
  trap 'dunstctl set-paused false; xset +dpms; notify-send "No-Idle mode" "No-Idle mode ended"' EXIT
  notify-send "No-Idle mode" "No-Idle mode started"
  sleep 5s
  xset -dpms
  dunstctl set-paused true
  systemd-inhibit  --who "$USER" --why "Manually disabled" --what "idle" -- yad --notification --action "quit" --image "action-unavailable-symbolic"

Create gifs from video files

This one's simple. Two-pass encoding via ffmpeg, turn a video into a gif. No safety checks though, so be careful with it, it might overwrite your cat.

  #!/bin/bash
  
  PALETTE=$(mktemp)
  trap "rm $PALETTE" EXIT
  ffmpeg -i "$1" -vf fps=15,scale=400:-1:flags=lanczos,palettegen "${PALETTE}".png
  ffmpeg -i "$1" -i "${PALETTE}".png -filter_complex 'fps=15,scale=800:-1:flags=lanczos[x];[x][1:v]paletteuse' -loop -1 "${1%%.*}.gif"