💾 Archived View for thrig.me › blog › 2023 › 11 › 19 › weird-shell-functions.gmi captured on 2024-08-18 at 18:10:03. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-12-28)

-=-=-=-=-=-=-

Weird Shell Functions

    function cmdindir {
       local cmd=$1
       local dir=$2 
       shift 2
       # NOTE $cmd gets a split and a glob expansion
       /bin/mkdir -p -- "$dir" && $cmd -- "$@" "$dir" \
         && builtin cd -- "$dir" \
         && pwd
    }
    function cpto {
       if [[ $# -lt 2 ]]; then
          print >&2 'Usage: cpto dir file [..]'; false
       else
          cmdindir cp "$@"
       fi
    }
    function mvto {
       if [[ $# -lt 2 ]]; then
          print >&2 'Usage: mvto dir file [..]'; false
       else
          cmdindir mv "$@"
       fi
    }

These functions provide wrappers for "cp" and "mv" that create the destination directory, copy (or move) the given files, and change the shell into the directory. That is,

    $ mvto foo/bar/zot baz

is much the same as:

    $ mkdir -p foo/bar/zot
    $ mv baz foo/bar/zot
    $ cd foo/bar/zot

The "pwd" is to let you know where you are, as usually the working directory does not change as a result of a random command, so it may help to have a reminder. PS1='$ ' so I generally do not know where the shell is; that's what pwd(1) or a wrapper program that gets the current directory into the clipboard is for.

    #!/bin/sh
    # pwd2clip - get working directory into clipboard and print it out
    pwd | copycat

I've seen people with the shell prompt showing all sorts of information ignore that information and make an error, so why not minimize the shell prompt? Something to try out, and it makes copying and pasting shell examples easier.

A fancy shell like ZSH could pop the directory off the end, which would make the argument order behave more like it does for cp and mv. Traditional shells only have "shift" compared to the full "shift", "pop", "unshift", and "push" functions in Perl. Fancy shells also let you use various cryptic shortcuts to refer to previous arguments, which may also help cut down on repetitions of the same long path.

Special cd

    function cd {
       if [[ -z "$1" ]]; then
          builtin cd
       elif [[ -d "$1" ]]; then
          builtin cd -- "$1"
       elif [[ -a "$1" ]]; then
          builtin cd -- "$(dirname -- "$1")"
       else
          builtin cd "$@"
       fi
    }

The main benefit here is to chdir to a file: given "cd /etc/passwd" the working directory becomes "/etc". This lets you paste a file path to cd and have it do something appropriate. Others might want cd to fail with an error, but then you would need to modify a filepath to get to the directory of that file. This function could instead be called "fcd" to avoid changing how "cd" behaves, but then you'd need to remember to use fcd when a filepath is involved.

More things could be done with this function, e.g. to make it aware of version control branches, or however much rope you want to rig up the footguns with.

Alternatives

Another way to solve the above problem would be with a subshell: some commands are run, preparation work is done, and then a new directory is spawned in a particular directory. This avoids the need to perform the chdir in the parent shell process, though can accumulate subshells.

Or, one might have some sort of communication means so that the parent shell is informed that it should chdir somewhere as a result of a command. But that would be a bit more complicated, and might get into security issues and unexpected bugs as random child processes do random things with the working directory of some parent process.

tags #ksh #unix