163

I have an executable file mpiexec, whose full path is ~/petsc-3.2-p6/petsc-arch/bin/mpiexec. Since I want to execute this command in different directories (without having to retype the entire path), I setup an alias in my home .bashrc file:

alias petsc="~/petsc-3.2-p6/petsc-arch/bin/mpiexec"  

which allows me to execute this mpiexec file at the command prompt easily by typing:

petsc myexecutable

I tried to write a shell script file, named script, using my new alias petsc as a command. After giving my shell script the appropriate permissions (using chmod), I tried to run the script. However, it gave me the following error:

./script: line 1: petsc: command not found

I know that I could just write the full path to the mpiexec file, but it is cumbersome to write the full path everytime that I want to write a new script. Is there a way that I can use my alias petsc inside the script file? Is there a way I can edit my .bashrc or .bash_profile to make this happen?

4
  • How about adding the alias to .bash_aliases ? Also how about aliasing the absolute path instead of relative path like alias petsc='/home/user/petsc-3.2-p6/petsc-arch/bin/mpiexec' Jan 26, 2012 at 18:17
  • @nitstorm: Neither solution seems to work... I still get the same error as before
    – Paul
    Jan 26, 2012 at 18:21
  • Related: unix.stackexchange.com/questions/1496/… Nov 27, 2018 at 4:03
  • 1
    I actually just used a system link which worked for me like: ln -sf /usr/bin/podman .local/bin/docker Mar 20, 2020 at 1:11

11 Answers 11

115

Some options:

  1. In your shell script use the full path rather then an alias.

  2. In your shell script, set a variable, different syntax

    petsc='/home/your_user/petsc-3.2-p6/petsc-arch/bin/mpiexec'
    
    $petsc myexecutable
    
  3. Use a function in your script. Probably better if petsc is complex

    function petsc () {
        command 1
        command 2
    }
    
    petsc myexecutable
    
  4. Source your aliases

    shopt -s expand_aliases
    source /home/your_user/.bashrc
    

You probably do not want to source your .bashrc, so IMO one of the first 3 would be better.

9
  • 1
    Your suggestion 2) works, but I want to be able to use the same command in multiple shell scripts without having to write the first line petsc="...". Is there a way to do this?
    – Paul
    Jan 26, 2012 at 18:31
  • Sounds as if you should put the command in a more standard location, such as /usr/local/bin
    – Panther
    Jan 26, 2012 at 18:35
  • 2
    In the point 2 you do not set an alias but a variable. Nov 1, 2014 at 9:58
  • 4
    Not asked for by OP but relevant to the question title: Point 2 won't work with commands containing |. Here, use shopt -s expand_aliases & local alias, e.g. alias myalias='echo abc|rev' - requires line-break before use (see ALIASES in man bash). Point 4: Sourced file may prevent non-interactive execution, i.e. in a script. Look for early exit or return, e.g. [ -z "$PS1" ] && return (checks if primary prompt isn't set indicating non-interactive shell) or there may be a check for i in $- ($- contains shell options, i means interactive). See man bash for those variables.
    – valid
    Mar 20, 2015 at 13:58
  • 1
    I liked option 4. It allowed me to declare and use alias commands within my script
    – ishahak
    Aug 27, 2020 at 3:37
94

Aliases are deprecated in favor of shell functions. From the bash manual page:

For almost every purpose, aliases are superseded by shell functions.

To create a function and export it to subshells, put the following in your ~/.bashrc:

petsc() {
    ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
}
export -f petsc

Then you can freely call your command from your shell scripts.

4
  • That almost works... the only problem is that I need to be able to pass different flags to the executable "mpiexec"... For instance, I need to be able to execute something like "petsc -n 40 myexecutable" with the alias "petsc"
    – Paul
    Jan 26, 2012 at 18:46
  • 8
    @Paul: I added "$@" just to handle arguments.
    – enzotib
    Jan 26, 2012 at 19:47
  • One of the exception is return. Say, you are writing a script that work for both as sourced or standalone, and you want to use quit to exit that script. Function like this cannot quit in sourced scritpt: quit(){ return $1 ;} Instead, you need to use alias: alias quit=return Sep 19, 2020 at 1:45
  • According to man bash: ` If the -f option is given, the names refer to functions.`
    – Timo
    Jun 15, 2021 at 18:35
21

In bash 4 you can use special variable: $BASH_ALIASES.

For example:

$ alias foo="echo test"
$ echo ${BASH_ALIASES[foo]}
echo test
$ echo `${BASH_ALIASES[foo]}` bar
test bar

Alternatively define as variable then use command substitution or eval.

So for example, instead of defining the alias such as:

alias foo="echo test"

define it as:

foo="echo test"

instead. Then execute it by either:

find . -type f -exec sh -c "eval $foo" \;

or:

find . -type f -exec sh -c "echo `$foo`" \;
3
  • Altough aliases are deprecated in favor of shell functions, this answer os the only one which should be accepted. Even the old Debian 8 has version 4 of bash, so the ${BASH_ALIASES[alias]} is a nice option. Otherwise i had to edit lot of lines of my .bash_aliases to apply other things. Thank you.
    – m3nda
    Sep 16, 2017 at 9:23
  • Indeed. In my case, it worked like this: eval ${BASH_ALIASES[foo]} . Even managed to get through nested aliasing, e.g. foo->foo123->/smth/real May 1, 2020 at 10:13
  • It worked in Git Bash on Win 10. Thanks!
    – StayCool
    Aug 9, 2021 at 11:43
20
ALIASES
   ...
   Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the description of shopt under SHELL BUILTIN COMMANDS
   below).

So the real answer to this question, for those looking to use actual aliases in shell scripts instead of alternatives to them, is:

#!/bin/bash

shopt -s expand_aliases

alias foo=bar

foo whatever

As for why I'd want to do this: Due to unusual circumstances, I need to trick a Dockerfile into thinking it's a shell script.

3
  • 1
    Yes. This is the right answer. Makes aliases work inside scripts whether invoked from prompt or cron. Thank you.
    – maxwell
    May 12, 2021 at 13:58
  • This only works for aliases created in the script. Aliases that were present on the system are still ignored; and those are the useful aliases. May 6 at 23:31
  • Aliases are not present "in the system". They are present in a given shell process. There is no way for a shell process to transmit its aliases to a child process. The login shell sources several files from /etc (the only one I remember is /etc/profile), in addition to .profile and .bashrc. If you source the same files in your script, you'll have those aliases too. May 15 at 11:47
15

Shell functions and aliases are limited to the shell and do not work in executed shell scripts. Alternatives for your case:

  • (if you do not bother to use mpiexec instead of petsc) Add $HOME/petsc-3.2-p6/petsc-arch/bin to your PATH variable. This can be done by editing ~/.profile and appending:

    PATH="$HOME/petsc-3.2-p6/petsc-arch/bin:$PATH"
    

    Re-login to apply these changes

  • Create the directory ~/bin and

    • make a wrapper script named petsc containing:

      #!/bin/sh
      exec ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
      
    • if the program allows for it, you can skip the shellscript and make a symlink using the command:

      ln -s ~/petsc-3.2-p6/petsc-arch/bin/mpiexec ~/bin/petsc
      
14

You can force bash to execute your script as an interactive shell with the -i flag. This will tell your .bashrc file to define aliases and other functions.

Example:

~ $ grep ll .bashrc
alias ll='ls -lah'
~ $ cat script.sh 
#!/bin/sh

ll
~ $ bash script.sh 
script.sh: line 3: ll: command not found
~ $ bash -i script.sh
..directory contents..

More info:

$ man bash
1
  • 2
    .bashrc is also read during non-interactive SSH command execution (that's why it has a check for interactivity at the top)
    – muru
    Jan 10, 2017 at 13:12
5
  1. In .bash_aliases:

    petsc {
    ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
    }
    

    Or put the function in .bashrc. Usually in .bashrc only config settings of bash are stored.

  2. In Terminal: source .bash_aliases

  3. Call it: petsc arg(s)

Advantage: you do not need export -f petscin .bash_aliases. Aliases are deprecated but using .bash_aliases for functions is ok.

1
  • I like this solution, I will give it a try later Apr 24, 2015 at 2:24
3
  1. Use your aliases in your shell script.
  2. Source your script in your current, interactive shell instead of executing it.

So if you have a file called script.sh with your commands that include using aliases, simply type:

source script.sh
2
  • @DavidFoerster This method works fine. Sourcing a script with the . or source buiiltin causes the current shell to execute all the commands in it. If alias expansion would occur in the shell in which . or source is run, it occurs. However, it's important to realize that this method is only sometimes useful, because often one needs or wants to execute a script in its own shell, with its own environment. Shell scripts written with the intention of being executed in the usual way should not usually be sourced instead--they often won't work right. Jan 10, 2017 at 9:44
  • @EliahKagan: Thanks. Now I understand what the answer is supposed to mean. I'll add an explanation. Jan 10, 2017 at 9:52
2

(EDIT: removed functions since I misread calling of mpiexec.)

If the only thing you need is less typing, why don't you just put the folder in $PATH? Or make a symlink to mpiexec from some folder in $PATH? Or (my favourite) put the alias in a script that you source in the calling script?

4
  • 1
    The reason why I can't put it into my $PATH is because I have another 'mpiexec' file in another directory that is alredy in my $PATH. If I add the path to this new 'mpiexec', it will probably try to execute both of them... wouldn't it?
    – Paul
    Jan 26, 2012 at 19:34
  • 1
    Cannot understand why not simply use "$@".
    – enzotib
    Jan 26, 2012 at 19:49
  • 2
    Paul, it'll try to execute the one that's first in the PATH, not both.
    – unhammer
    Jan 27, 2012 at 9:41
  • enzotib, ah I misread the way mpiexec was called, I thought it needed all args as one. Will edit my answer :)
    – unhammer
    Jan 27, 2012 at 9:44
0

Please use #!/usr/bin/env sh instead of #!/usr/bin/env bash, then it works.

sample: my.sh

#!/usr/bin/env sh

alias k="kubectl --kubeconfig ~/shop/config"
k version
./my.sh

If you have to use #!/usr/bin/env bash, then execute the script as the following way:

sh my.sh
0

You can use case statement like this when in a sub-shell:

function execute() {
        case $1 in
                ls) $@ --color=auto ;;
              grep) $@ --color=auto ;;
             fgrep) $@ --color=auto ;;
             egrep) $@ --color=auto ;;
                 *) $@ ;;
        esac
}


( execute $@ )

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.