Symlink to file which does not exist yet

8,667

A rewrite to reduce duplication

#!/bin/bash
# Make script executable with: chmod u+x brew.sh

# Ask for the administrator password upfront.
sudo -v

# Keep-alive: update existing `sudo` time stamp until the script has finished.
while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &

# Create '.other'-folder
echo "--> ~/.other"
mkdir -p ~/.other 2>/dev/null
echo ""

create_dir() {
    local pathname=$1 destination=$2 permissions=$3
    local dirname=$(basename "$pathname")

    echo "--> $pathname"
    if [ -L "$pathname" ] && [ "$(dirname "$(readlink "$pathname")")" = "$destination" ]; then
        echo "$pathname is already a symbolic link to $destination/$filename"
        return
    elif [ -d "$pathname" ]; then
        echo "Directory $pathname exists. Moving it to $destination..."
        mv "$pathname" $destination/
    else
        echo "Directory $pathname doesn't exist Creating it in $destination..."
        mkdir -p "$destination/$dirname"
    fi
    chmod "$permissions" "$destination/$direname"

    echo "Linking $destination/$dirname to $pathname ..."
    (
        cd "$(dirname "$pathname")"
        ln -s "$destination/$dirname" 
    )
    echo
}

create_file() {
    local pathname=$1 destination=$2 permissions=$3
    local filename=$(basename "$pathname")
    echo "--> $pathname"
    if [ -L "$pathname" ] && [ "$(dirname "$(readlink "$pathname")")" = "$destination" ]; then
        echo "$pathname is already a symbolic link to $destination/$filename"
        return
    elif [ -a "$pathname" ]; then
        echo "File $pathname exists. Moving it to $destination..."
        mv "$pathname" $destination/
    else
        echo "File $pathname doesn't exists. Creating it in $destination..."
        touch "$destination/$filename"
    fi
    chmod "$permissions" "$destination/$filename"

    echo "Linking $destination/$filename to ~/.bash_history..."
    (
        cd "$(dirname "$pathname")"
        ln -s "$destination/$filename"
    )
    echo ""
}

create_dir   ~/.Trash          ~/.other  755   # TRASH
create_file  ~/.bash_history   ~/.other  600   # BASH_HISTORY
create_file  ~/.bash_sessions  ~/.other  644   # BASH_SESSIONS
create_dir   ~/.local          ~/.other  755   # .LOCAL
create_dir   ~/.config         ~/.other  755   # .CONFIG

create_file  ~/.bashrc         ~/.dotfiles 644 # etc ...

Notes:

  • mkdir -p will create the directory if it does not exist
  • check that the directory/file is not already a symbolic link first.
  • if specific files require specific permissions, no choice but to specify it.
Share:
8,667

Related videos on Youtube

LastSecondsToLive
Author by

LastSecondsToLive

Updated on September 18, 2022

Comments

  • LastSecondsToLive
    LastSecondsToLive almost 2 years

    I'm currently trying to cleanup my home directory by moving files like .vimrc, .bash_profile, etc. to a directory .dotfiles in my home directory.

    The idea is to use symbolic links to these files afterwards: ln -s ~/.dotfiles/.vimrc ~/.
    This works quiet fine, but I'd like to automate this process by writing my first bash script and I ran into some trouble.

    The script currently looks something like this:

    #!//bin/bash
    # Make script executable with: chmod u+x brew.sh
    
    # Ask for the administrator password upfront.
    sudo -v
    
    # Keep-alive: update existing `sudo` time stamp until the script has finished.
    while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &
    
    # Create '.other'-folder
    echo "--> ~/.other"
    if [ -d ~/.other ];
    then
      echo "Directory ~/.other exists..."
    else
      echo "Creating directory ~/.other..."
      mkdir ~/.other
    fi
    echo ""
    
    # TRASH
    echo "--> ~/.Trash"
    if [ -d ~/.Trash ];
    then
      echo "Directory ~/.Trash does exists. Moving it to ~/.other..."
      mv ~/.Trash ~/.other/
    else
      echo "Directory ~/.Trash doesn't exists. Creating it in ~/.other..."
      mkdir ~/.other/.Trash
    fi
    
    echo "Linking ~/.other/.Trash to ~/.Trash..."
    ln -s ~/.other/.Trash ~/.
    echo ""
    
    # BASH_HISTORY
    echo "--> ~/.bash_history"
    if [ -a ~/.bash_history ];
    then
      echo "File ~/.bash_history does exists. Moving it to ~/.other..."
      mv ~/.bash_history ~/.other/
    else
      echo "File ~/.bash_history doesn't exists. Creating it in ~/.other..."
      touch ~/.other/.bash_history
    fi
    
    echo "Linking ~/.other/.bash_history to ~/.bash_history..."
    ln -s ~/.other/.bash_history ~/.
    echo ""
    
    # BASH_SESSIONS
    echo "--> ~/.bash_sessions"
    if [ -d ~/.bash_sessions ];
    then
      echo "Directory ~/.bash_history does exists. Moving it to ~/.other..."
      mv ~/.bash_sessions ~/.other/
    else
      echo "Directory ~/.bash_history doesn't exists. Creating it in ~/.other..."
      mkdir ~/.other/.bash_sessions
    fi
    
    echo "Linking ~/.other/.bash_sessions/ to ~/.bash_sessions/..."
    ln -s ~/.other/.bash_sessions ~/.
    echo ""
    
    # .LOCAL
    echo "--> ~/.local"
    if [ -d ~/.local ];
    then
      echo "Directory ~/.local does exists. Moving it to ~/.other..."
      mv ~/.local ~/.other/
    else
      echo "Directory ~/.local doesn't exists. Creating it in ~/.other..."
      mkdir ~/.other/.local
    fi
    
    echo "Linking ~/.other/.local/ to ~/.local/..."
    ln -s ~/.other/.local ~/.
    echo ""
    
    # .CONFIG
    echo "--> ~/.config"
    if [ -d ~/.config ];
    then
      echo "Directory ~/.config does exists. Moving it to ~/.other..."
      mv ~/.config ~/.other/
    else
      echo "Directory ~/.config doesn't exists. Creating it in ~/.other..."
      mkdir ~/.other/.config
    fi
    
    echo "Linking ~/.other/.config/ to ~/.config/..."
    ln -s ~/.other/.config ~/.
    echo ""
    

    As you can see the code is pretty repetitive, but first things first. The code should work roughly like this. Check whether file (for example init.vim) exists in my home directory. If it does exists move it to either ~/.other (not so important files) or to ~/.dotfiles (important files). If it doesn't exist create a file (or directory) in ~/.dotfiles or ~/.other. Symlink afterwards.

    So far the theory. The problem is, if the file does't exist in my home-directory yet - the script just creates a file in ~/.dotfiles/~/.other, and links the name in the home directory to it. This doesn't really work out in practice, since some files need specific permissions. For example neovim doesn't recognize some files if they are created with this script and it's not very efficient to just create the files before they are even used.

    Is there a way to fix this (for example by creating a link, without creating the target file - I tried it once to link .bash_history to .other/.bash_history, the link worked fine, but bash couldn't write to a non existing file)? It would be optimal if new files would be created in the right place and I only need to specify the right place before?

    PS: When the file already exists the script works fine (it just moved the file to the new location and links it).

    • LastSecondsToLive
      LastSecondsToLive over 8 years
      @glennjackman I do know about the touch command, but how should I know about what permissions I need to set? I'd need to research for every single file. There has to be a more easy way. I thought about aliasing the script to command like cleanup and it loops over all files in the home directory and asks the user if he wants to move it to ~/.dotfiles or ~./other, but then the user had to actually do something and had to execute the code multiple times (if knew files are added to the home directory - I can't prevent the creation in the home directory).
    • Mat
      Mat over 8 years
      Unrelated but what's up with the sudo tricks at the start? Doesn't seem like your script needs elevated privs.
    • LastSecondsToLive
      LastSecondsToLive over 8 years
      @Mat You are probably right, I just think one time I got permission denied, when I tried to create a dir. I'm honestly not sure about it. I should probably remove it. Thanks!
  • LastSecondsToLive
    LastSecondsToLive over 8 years
    How did you find the needed permission so fast? This is honestly amazing! Thank you so much!
  • Angel Todorov
    Angel Todorov over 8 years
    I did an ls -la and noted what perms my files have.