25

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
6
  • 1
    @Jesse_b code blocks don't show spaces at end (git{space} becomes git). The prefix is user-inputted. It is used like use_prefix sudo docker so I don't need to type the prefix before each command. Dec 4, 2019 at 19:05
  • side note: you don't need to use sudo to run docker if your user is a member of the docker group
    – virullius
    Dec 4, 2019 at 19:46
  • Possible duplicate of Modify shell command before running it
    – muru
    Dec 5, 2019 at 4:41
  • 2
    Does this answer your question? Modify all bash commands through a program before executing them
    – user313992
    Dec 6, 2019 at 7:40
  • 1
    If you can run sudo to run docker, you can most likely also add yourself to the docker group so you don't have to run sudo. Dec 6, 2019 at 13:43

8 Answers 8

19

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.

2
  • 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, 2019 at 14:33
  • 4
    You could add something like history -s "$@" "${c[@]}" after running the commands to manually put them into the history
    – shay
    Dec 6, 2019 at 2:05
14

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

1
  • 1
    can I use time-command with every command in terminal! May 9, 2021 at 12:25
10

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.

5
  • 3
    You can escape aliases: \ps - bit quicker than command ps.
    – FelixJN
    Dec 4, 2019 at 19:35
  • Thanks for the reminder @Fiximan, updated
    – bxm
    Dec 4, 2019 at 19:39
  • Users can also get the normal binary by specifying it's full path like /usr/bin/ps
    – ti7
    Dec 5, 2019 at 15:57
  • 1
    True, but command doesn’t demand that you know where a given binary sits.
    – bxm
    Dec 5, 2019 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, 2019 at 21:00
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.

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

1
  • 1
    Aliases can be written to a file and sourced in the shell's rc.
    – FelixJN
    Dec 4, 2019 at 19:46
3

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.

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.

1
  • 3
    Aliases were already covered in two other answers.
    – jesse_b
    Dec 6, 2019 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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .