21

How can I prefix all commands in a shell without typing it each time?

My use case 1:

$ git init
$ git add -A
$ git commit
$ git push

Prefix should be git␣ ( is the space character)

init
add -A
commit
push

My use case 2:

sudo docker run my-repo/my-image
sudo docker ps
sudo docker images

Prefix should be sudo docker␣

run my-repo/my-image
ps
images

It would be best if I could do something like this:

$ git init
$ use_prefix sudo docker
> ps
> images
> exit
$ sudo docker run my-repo/my-image
16

You could use a function like the following:

use_prefix () {
    while read -ra c; do
        "$@" "${c[@]}"
    done
}

This will accept your prefix as arguments to the use_prefix command and then read from stdin for each command to be prefixed.

Note: You will have to use ctrl+c to exit the while read loop.

| improve this answer | |
  • 6
    A drawback of this method is that the commands entered in the loop won’t be saved to your command line history. (Just sayin’, there's nothing wrong with the method though.) – zrajm Dec 5 '19 at 14:33
  • 3
    You could add something like history -s "$@" "${c[@]}" after running the commands to manually put them into the history – shay Dec 6 '19 at 2:05
13

You could use xargs, but with due regard to caveats associated with its use

xargs -L1 git

then type in init, add -A etc, one per line

| improve this answer | |
10

With the zsh shell, you could run:

zle-line-init() if [[ $CONTEXT = start ]] LBUFFER=$zle_prefix$LBUFFER
zle -N zle-line-init

For the contents of $zle_prefix to be inserted at the start of the buffer when you start entering a new command line.

So you can do:

zle_prefix='sudo docker '

For that sudo docker to be inserted at the start of subsequent commands.

You could define another widget that primes $zle_prefix with what's currently before your cursor:

prime-zle-prefix() zle_prefix=$LBUFFER
zle -N prime-zle-prefix
bindkey '\eP' prime-zle-prefix

And then you can type

$ sudo docker Alt+Shift+P ls

Then sudo docker will be inserted for all subsequent command. When you're done, blank the line (Ctrl+U) and enter Alt+Shift+P again to empty $zle_prefix.

| improve this answer | |
8

One solution would be to set up aliases, but you’ll have to be mindful when they collide with built in commands and system binaries (for example ps).

In your ~/.bashrc add some lines like so (takes effect when you next start bash or type source ~/.bashrc):

alias commit='git commit'
alias docker='sudo docker'
alias images='docker images'
alias ps='docker ps'

To run an actual ps you would have to type command ps or \ps. That would generally only affect typing at the command line, unless you specifically make the aliases available to scripts.

As for an interactive shell interface like you suggest, that would require something more involved.

To wit, an expansion of @Jesse_B’s fine suggestion:

use_prefix () {
    while read -p "$* >" -ra c; do
        [ "${c[0]}" = "exit" ] && break
        "$@" "${c[@]}"
    done
}

Enabling the exit key word and also adding a prompt reminding you of what you are doing.

| improve this answer | |
  • 3
    You can escape aliases: \ps - bit quicker than command ps. – Fiximan Dec 4 '19 at 19:35
  • Thanks for the reminder @Fiximan, updated – bxm Dec 4 '19 at 19:39
  • Users can also get the normal binary by specifying it's full path like /usr/bin/ps – ti7 Dec 5 '19 at 15:57
  • 1
    True, but command doesn’t demand that you know where a given binary sits. – bxm Dec 5 '19 at 16:21
  • 2
    I think aliases are the best solution, but instead I would suggest short and general aliases: e.g., g=git; sd=sudo docker. Generally is not good to create aliases for subcommands unless you almost always use them that way or they are too long to remember, otherwise you end up with too many aliases, which leads to not using them (and to forgetting how to do things in other systems without your config) – jsb Dec 5 '19 at 21:00
4

Hi and welcome to the site.

one possible work around to this is to use aliasing

although it doesn't negate the "prefix" it can save a lot on time

e.g.

alias g=git

$ g init
$ g add -A
$ g commit
$ g push

OR

if there's multiple words just use quotes

alias sd="sudo docker"

sd run my-repo/my-image
sd ps
sd images

you will need to reset these aliases with each session however

| improve this answer | |
  • 1
    Aliases can be written to a file and sourced in the shell's rc. – Fiximan Dec 4 '19 at 19:46
1

You essentially want a general-purpose sub-shell for the specific command:

shell() {
    TOPCMD=$@ bash -c 'while read -p "${TOPCMD##*/}> " -ra sub; do
        case ${sub[0]:-} in
        "") continue;;
        exit) exit;;
        escape) (set -x; ${sub[@]:1});;
        *) (set -x; ${TOPCMD} ${sub[@]});;
        esac
        done'
}

So then:

$ shell git -p
git -p> init
+ git -p init
Initialized Git repository in /path/to/.git/
git -p> escape touch foo
+ touch foo
git -p> add .
+ git -p add .
git -p> status
+ git -p status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   foo

git -p> 

Any command you type gets prefixed by the original command (absolute or relative, plus any arguments). The prompt reminds you what original command you're in. You can exit out entirely, or escape one command.

| improve this answer | |
0

You can create the alias in .bashrc file of Linux : alias init="git init"

and when you run init command from the terminal automatically "git init" command would be invoked.

| improve this answer | |
  • 3
    Aliases were already covered in two other answers. – jesse_b Dec 6 '19 at 14:47
0

Assuming you use bash, there are many ways to do this as mentioned above. Here is what I found to be the most convenient - YMMV:

  1. Create a function for each "shortcut" that you want to use.
  2. Have all such functions in a file called, say, ~/.bash_aliases
  3. Source this file in your .bash_profile.
  4. Call the function followed by the argument(s).

Note that, strictly speaking, the file doesn't contain aliases, but I am using that name to keep things uncluttered. You might want to call it .bash_functions.

Here is an extremely simple example to get you started. It doesn't check if you have actually passed on an argument or not.

$ cat ~/.bash_aliases

g() {
 git "$@"
}

sudock() {
 sudo docker "$@"
}

You can then add a line in your .bash_profile to source it like so:

. ~/.bash_aliases

Here are some sample usages:

g status
g commit -m 'initial commit' fileName
sudock run my-repo/my-image

Note that you can use $1 in place of $@, but that will take only one argument instead of considering everything that was passed on to the function.

HTH.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.