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