Skip to main content

Overview

stot is a dotfile management utility that simplifies symlinking and copying configuration files from a central dotfiles repository (~/dotfiles/) to their target locations in your home directory or system directories.
The name β€œstot” likely stands for β€œsymlink to” or similar, reflecting its primary purpose of creating symbolic links for dotfile management.

Features

  • Symlink files and directories from ~/dotfiles/ to ~/
  • Copy files to system directories (requires sudo)
  • Automatic directory creation
  • Safe file replacement
  • Visual feedback with status icons
  • Support for custom destination paths

Installation

1

Create Dotfiles Directory

Create your central dotfiles repository:
mkdir -p ~/dotfiles
2

Place Script in PATH

Ensure the stot script is executable and in your PATH:
chmod +x ~/workspace/source/bin/stot
3

Organize Dotfiles

Structure your dotfiles directory to mirror your home directory:
~/dotfiles/
β”œβ”€β”€ .vimrc
β”œβ”€β”€ .zshrc
β”œβ”€β”€ .config/
β”‚   β”œβ”€β”€ i3/
β”‚   └── nvim/
└── .local/
    └── bin/

Syntax

stot [OPTION]... SOURCE
stot [OPTION]... SOURCE DEST

Options

-l
flag
default:"default"
Link mode (default): Creates symbolic links from ~/dotfiles/SOURCE to ~/SOURCE
-c
flag
Copy mode: Copies files from ~/dotfiles/SOURCE to /SOURCE using sudo
-h
flag
Display help message and exit

Arguments

SOURCE
string
required
Relative path to the file or directory within ~/dotfiles/
DEST
string
Optional custom destination path (relative to home directory for -l, absolute for -c)

Usage Examples

Symlinking Files

# Link .vimrc from ~/dotfiles/.vimrc to ~/.vimrc
stot -l .vimrc

Copying System Files

# Copy file to /etc/ (requires sudo)
stot -c etc/hosts etc/hosts

How It Works

1

Path Resolution

Resolves source path as ~/dotfiles/$SOURCE and destination as ~/$DEST (or ~/$SOURCE if DEST not provided)
2

Type Detection

Determines if source is a file or directory
3

Directory Handling

For directories:
  • Creates destination directory if it doesn’t exist
  • Symlinks all contents to destination
  • Shows: |:ok | ln | πŸ“ | SOURCE
4

File Handling

For files:
  • Creates parent directory if needed
  • Removes existing destination file
  • Creates symbolic link
  • Shows: |:ok | ln | πŸ“„ | SOURCE

Copy Mode (-c)

1

Path Resolution

Resolves source path as ~/dotfiles/$SOURCE and destination as /$DEST (absolute path)
2

Validation

Verifies source file exists and destination parent directory exists
3

Copy Operation

Uses sudo cp to copy file to system directory
4

Feedback

Shows: |:ok | cp | πŸ“„ | DEST

Source Code

#!/usr/bin/env bash

   messageOk="|:ok |"
messageError="|:error |"

 message_ln=" ln  | πŸ“„ |"
message_lnd=" ln  | πŸ“ |"
message_lna=" ln  | πŸ“ |"
 message_cp=" cp  | πŸ“„ |"


if (($# == 0)); then
  echo "Please pass argumensts"
  echo "Usage: stot [OPTION]... SOURCE"
  exit 1;
fi


while getopts ":hlc" opt; do
  case $opt in
    h)
        echo "Usage: stot [OPTION]... SOURCE"
        echo "   or: stot [OPTION]... SOURCE DEST"
        echo ""
        echo "   -l                          ln     "
        echo "   -c                          cd     "
        echo "   -h                          display this help and exit   "
        exit 0;
    ;;

    l) METHOD="ln"
    ;;

    c) METHOD="cp"
    ;;

    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1;
    ;;

    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1;
    ;;

  esac
done

shift $(($OPTIND - 1))
PASSED=$1




if [[ $1 ]]; then
  # ------------------------------------------
  #                 LN
  # ------------------------------------------
  if [ $METHOD == "ln" ]; then
    [ $1 ] && sourcePath=$HOME/dotfiles/$1
    [ $1 ] && destPath=$HOME/$1
    [ $2 ] && destPath=$HOME/$2


    # IS FOLDER
    # -------------
    if [[ -d $sourcePath ]]; then

      [ !  -d "$destPath" ] && mkdir $destPath &> /dev/null
      if [ -d "$destPath" ]; then
        ln -sv $sourcePath/* $destPath &> /dev/null
        echo "$messageOk $message_lnd $1"
      else
        echo "$messageError $destPath not found"
      fi


    # IS FILE
    # -------------
    elif [[ -f $sourcePath ]]; then
      destFolderPath=$(dirname "$destPath")

      [ ! -d "$destFolderPath" ] && mkdir $destFolderPath &> /dev/null
      [ -f "$destPath" ] && rm $destPath &> /dev/null

      if [ -d "$destFolderPath" ]; then
        ln -sv $sourcePath $destPath &> /dev/null
        echo "$messageOk $message_ln $1 "
      else
        echo "$messageError  $homeFilePath"
      fi


    # IS NOT VALID
    # -------------
    else
      echo "$sourcePath is not valid"
      exit 1
    fi



  exit 1;

  # ------------------------------------------
  #                 CP
  # ------------------------------------------
  elif [ "$METHOD" == "cp" ]; then
    [ $1 ] && sourcePath=$HOME/dotfiles/$1
    [ $1 ] && destPath=/$1
    [ $2 ] && destPath=/$2

    # IS FILE
    # -------------
    if [[ -f $sourcePath ]]; then
      destFolderPath=$(dirname "$destPath")

      if [ -d $destFolderPath ]; then
          sudo cp $sourcePath $destFolderPath &> /dev/null
          echo "$messageOk $message_cp $destPath"
      else
          echo "$messageError $destPath"
      fi

    # IS NOT VALID
    # -------------
    else
      echo "$sourcePath is not valid"
      exit 1
    fi

  exit 1;
  fi

else
    echo "Please pass valid source"
    echo "Usage: stot [OPTION]... SOURCE"
    exit 1
fi

Common Workflows

Initial Dotfiles Setup

# Link shell configuration
stot -l .bashrc
stot -l .zshrc

# Link editor configs
stot -l .vimrc
stot -l .config/nvim

# Link git configuration
stot -l .gitconfig

New Machine Setup

1

Clone Dotfiles

git clone https://github.com/user/dotfiles.git ~/dotfiles
2

Link All Configs

# Create a setup script
cd ~/dotfiles
for config in .vimrc .zshrc .gitconfig; do
  stot -l $config
done

for dir in .config/*; do
  stot -l $dir
done
3

Verify Links

# Check symlinks
ls -la ~ | grep '^l'

Output Messages

Success Messages

IconOperationMessage
βœ…Link file`:oklnπŸ“„filename`
βœ…Link directory`:oklnπŸ“dirname`
βœ…Copy file`:okcpπŸ“„/path/to/file`

Error Messages

MessageCauseSolution
Please pass argumenstsNo arguments providedProvide SOURCE argument
Invalid option: -XUnknown optionUse -l, -c, or -h
sourcePath is not validSource doesn’t existCheck file exists in ~/dotfiles/
destPath not foundParent directory missingCheck destination path

Tips & Best Practices

Version Control: Keep your ~/dotfiles/ directory under version control with git to track changes and sync across machines.
Destructive Operations: The -l mode removes existing destination files before creating symlinks. Back up important configurations first.
Directory Linking: When linking directories, stot symlinks the contents, not the directory itself, allowing for partial configuration management.
~/dotfiles/
β”œβ”€β”€ .bashrc
β”œβ”€β”€ .zshrc
β”œβ”€β”€ .gitconfig
β”œβ”€β”€ .vimrc
β”œβ”€β”€ .config/
β”‚   β”œβ”€β”€ nvim/
β”‚   β”‚   β”œβ”€β”€ init.vim
β”‚   β”‚   └── plugins.vim
β”‚   β”œβ”€β”€ i3/
β”‚   β”‚   └── config
β”‚   └── alacritty/
β”‚       └── alacritty.yml
β”œβ”€β”€ .local/
β”‚   └── bin/
β”‚       └── custom-scripts
└── etc/
    └── hosts

Troubleshooting

Copy mode (-c) requires sudo privileges:
# Ensure sudo is configured
sudo -v

# Run stot with -c
stot -c etc/hosts
Remember that stot -l links directory contents, not the directory itself:
# This links files inside .config/nvim/ to ~/.config/nvim/
stot -l .config/nvim

# Not the .config/nvim directory itself

ln

Standard Unix symbolic link command

cp

Standard Unix copy command

GNU Stow

Alternative dotfile management tool

chezmoi

Modern dotfile manager with templates

See Also

Build docs developers (and LLMs) love