Вопрос

I'm trying to create a system for my scripts -
Each script will be located in a folder, which is the command itself.
The script itself will act as a sub-command.

For example, a script called "who" inside a directory called "git",
will allow me to run the script using git who in the command line.
Also, I would like to create a sub command to a psuedo-command, meaning a command not currently available. E.g. some-arbitrary-command sub-command.

Is that somehow possible?
I thought of somehow extending https://github.com/basecamp/sub to accomplish the task.

EDIT 1

#!/usr/bin/env bash

command=`basename $0`
subcommand="$1"
case "$subcommand" in
"" | "-h" | "--help" )
  echo "$command: Some description here" >&2
  ;;
* )
  subcommand_path="$(command -v "$command-$subcommand" || true)"
  if [[ -x "$subcommand_path" ]]; then
    shift
    exec "$subcommand_path" "${@}"
    return $?
  else
    echo "$command: no such command \`$subcommand'" >&2
    exit 1
  fi
  ;;
esac

This is currently the script I run for new custom-made commands.
Since it's so generic, I just copy-paste it.
I still wonder though -
can it be generic enough to just recognize the folder name and create the script by its folder name?

One issue though is that it doesn't seem to override the default command name, if it supposed to replace it (E.g. git).

EDIT 2

After tinkering around a bit this is what I came to eventuall:

#!/usr/bin/env bash

COMMAND=`basename $0`
SUBCOMMAND="$1"
COMMAND_DIR="$HOME/.zsh/scripts/$COMMAND"

case "$SUBCOMMAND" in
  "" | "-h" | "--help" )
    cat "$COMMAND_DIR/help.txt" 2>/dev/null ||
    command $COMMAND "${@}"
    ;;
  * )
    SUBCOMMAND_path="$(command -v "$COMMAND-$SUBCOMMAND" || true)"
    if [[ -x "$SUBCOMMAND_path" ]]; then
      shift
      exec "$SUBCOMMAND_path" "${@}"
    else
      command $COMMAND "${@}"
    fi
    ;;
esac

This is a generic script called "helper-sub" I symlink to all the script directories I have (E.g. ln -s $HOME/bin/helper-sub $HOME/bin/ssh).

in my zshrc I created this to call all the scripts:

#!/usr/bin/env bash

PATH=${PATH}:$(find $HOME/.zsh/scripts -type d | tr '\n' ':' | sed 's/:$//')
export PATH
typeset -U path

for aliasPath in `find $HOME/.zsh/scripts -type d`; do
  aliasName=`echo $aliasPath | awk -F/ '{print $NF}'`
  alias ${aliasName}=${aliasPath}/${aliasName}
done
unset aliasPath

Examples can be seen here: https://github.com/iwfmp/zsh/tree/master/scripts

Это было полезно?

Решение

You can't make a directory executable as a script, but you can create a wrapper that calls the scripts in the directory.

You can do this either with a function (in your profile script or a file in your FPATH) or with a wrapper script.

A simple function might look like:

git() {
    local subPath='/path/to/your/git'
    local sub="${1}" ; shift

    if [[ -x "${subPath}/${1}" ]]; then
        "${subPath}/${sub}" "${@}"
        return $?
    else
        printf '%s\n' "git: Unknown sub-command '${sub}'." >&2
        return 1
    fi
}

(This is the same way that the sub project you linked works, just simplified.)

Of course, if you actually want to create a sub-command for git specifically (and that wasn't just an example), you'll need to make sure that the built-in git commands still work. In that case you could do like this:

git() {
    local subPath='/path/to/your/git'
    local sub="${1}"

    if [[ -x "${subPath}/${sub}" ]]; then
        shift
        "${subPath}/${sub}" "${@}"
        return $?
    else
        command git "${@}"
        return 1
    fi
}

But it might be worth pointing out in that case that git supports adding arbitrary aliases via git config:

git config --global alias.who '!/path/to/your/git/who'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top