4

I have an executable file command.sh

#/bin/bash
alias my_command='echo ok'
my_command

My terminal is bash.

When I run it like ./command.sh, it works fine.

When I run it like /bin/bash ./command.sh, it can't find a my_command executable.

When I run it like /bin/sh ./command.sh, it works fine.

I'm confused here. Where's the problem?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Igor Loskutov
  • 2,157
  • 2
  • 20
  • 33

2 Answers2

9

From the bash man page:

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).

In other words, aliases are not enabled in bash shell scripts by default. When you run the script with bash, it fails.

Your sh appears to default to allowing aliases in scripts. When you run the script with sh, it succeeds.

./command.sh happens to work because your shebang is malformed (you're missing the ! in #!/bin/bash).

that other guy
  • 116,971
  • 11
  • 170
  • 194
  • 3
    Later in the same section: "For almost every purpose, shell functions are preferred over aliases." I never realized that aliases aren't expanded in non-interactive shells. That's one more reason to avoid them. Bash aliases seem quite crippled relative to csh/tcsh aliases. On the other hand, csh/tcsh doesn't have functions. – Keith Thompson May 08 '15 at 19:02
  • Actually, I come to this question trying to simplify another one - why my aliases from /etc/bash.bashrc, or from ~/profile doesn't being used. So function isn't an option here. – Igor Loskutov May 08 '15 at 19:13
  • 1
    Also I'm doing `shopt -s expand_aliases` before executing, or even on the same line like `shopt -s expand_aliases; ...` but it still doesn't get it. – Igor Loskutov May 08 '15 at 19:15
  • @IgorLoskutov There are two shells at work: your interactive shell, and the shell that is started to run your script. Setting this option in your interactive shell will not work, since that's not the shell your script uses. You have to put the `shopt -s expand_aliases` in your script. – that other guy May 08 '15 at 19:16
  • @IgorLoskutov: Is replacing all your aliases by functions an option? – Keith Thompson May 08 '15 at 19:17
  • @IgorLoskutov. I came here with the same problem - the alias expansion stops working in the bash script, even after `shopt -s expand_aliases` has been set at the top of the file. It works for a few lines, and then later stops working. I put `shopt -s expand_aliases` before the lines which aren't working, yet bash doesn't expand them. It looks like "aliases are not intended for script files - use functions instead" is the rule. BTW, the section is nested twice, in a `for` loop and then `if`. I tried unindenting the `alias=` back to the first column, but no joy. – Stephen Hosking Aug 22 '20 at 07:28
6

Aliases are for the interactive shell, what you want here is a function, e.g.

#!/bin/bash
function my_command() {
    echo ok
}

my_command
wich
  • 16,709
  • 6
  • 47
  • 72
  • 1
    The POSIX-compliant function declaration syntax is just `my_command() {`, with no `function` preceding; the `function` keyword exists for backwards compatibility with ancient ksh, which uses `function my_command {` with no `()`. Combining the ksh and POSIX formats gets you a result that's compatible with neither; see http://wiki.bash-hackers.org/scripting/obsolete – Charles Duffy Jan 04 '19 at 16:25