16

I have a very wierd case... If I run a script with /bin/bash, it can't recognize aliases that I set even inside the script. And the most strange thing is

$ cat -n test.sh
    1 #!/bin/bash
    2 alias somecommand='ls -alF'
    3 alias
    4 somecommand
$ ./test.sh
alias somecommand='ls -alF'
./test.sh: line 4: somecommand: command not found

... as shown above, if I run the command "alias" in the script it turns out that bash has taken somecommand into the aliases, but if I run the somecommand itself it will still not be recognized!

Everything is right if I use the command "sh" to run the script.. so is it a bug of bash? Or is there something I'm missing?

Any help is appreciated!

nichen
  • 275

6 Answers6

21

Simply don't use aliases in scripts. It makes little sense to use a feature designed for interactive use in scripts. Instead, use functions:

somecommand () {
    ls -alF
}

Functions are much more flexible than aliases. The following would overload the usual ls with a version that always does ls -F (arguments are passed in $@, including any flags that you use), pretty much as the alias alias ls="ls -F" would do:

ls () {
    command ls -F "$@"
}

The command here prevents the shell from going into an infinite recursion, which it would otherwise do since the function is also called ls.

An alias would never be able to do something like this:

select_edit () (
    dir=${1:-.}
    if [ ! -d "$dir" ]; then
        echo 'Not a directory' >&2
        return 1
    fi
    shopt -s dotglob nullglob
    set --
    for name in "$dir"/*; do
        [ -f "$name" ] && set -- "$@" "$name"
    done
    select file in "$@"; do
        "${EDITOR:-vi}" "$file"
        break
    done
)

This creates the function select_edit which takes directory as an argument and asks the user to pick a file in that directory. The picked file will be opened in an editor for editing.

The bash manual contains the statement

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

Kusalananda
  • 333,661
  • Thank you... but the thing is that I want to alias the main part of a long command, and use it each time with different suffix(some more options, with objects in the end)... can functions handle that too? – nichen May 31 '17 at 07:31
  • @nichen See updated answer. – Kusalananda May 31 '17 at 07:42
  • ...that's really nice! I didn't understand all the codes you wrote but got the idea, thanks a lot :) – nichen May 31 '17 at 08:02
10

To use interactive features like alias within a bash script you have to run it in an interactive bash shell. For that change the first line to include a -i . So your new script file becomes

#!/bin/bash -i
alias somecommand='ls -alF'
alias
somecommand 
amisax
  • 3,025
  • Had to add the alias for gksu (since Ubuntu has removed it from 18.04 onwards) and it is needed for launching certain GUI applications needing graphical authentication check prior to doing sudo. The bash native function method didn't seem to work, but this method did. – bdutta74 Jan 13 '19 at 18:11
7

Kind of a duplicate of a previous question however the answers there are kind of wordy. The short answer is that, for occult reasons, by default bash doesn't look at aliases defined inside scripts. You have to explicitly tell it to do so via a shopt -s expand_aliases line at the top of said script. Do that and then your script will find somecommand.

Nadreck
  • 402
  • I read that question but thought it was a different case because the alias was defined in ~/.bashrc and was supposed to be used in another script... – nichen May 31 '17 at 07:23
  • Yes, it is slightly different in the way that you describe but the principle is the same. That script was running ~/.bashrc when it starts up, (inside line 1 of the script) and then ignoring all _alias_es created inside script running shells. – Nadreck May 31 '17 at 13:47
6

Just add shopt -s expand_aliases after first line

#!/bin/bash
shopt -s expand_aliases
alias somecommand='ls -alF'
alias
somecommand

This will output

$ /tmp/alias.sh 
alias somecommand='ls -alF'
total 111044
drwxr-xr-x  4 sobi3ch sobi3ch     4096 Aug 22 14:27 ./
drwxr-xr-x 31 sobi3ch sobi3ch     4096 Aug 23 10:19 ../

Aliases for default are only for interactive shells (from man bash)

expand_aliases

If set, aliases are expanded as described above under ALIASES. This option is enabled by default for interactive shells.

sobi3ch
  • 697
1

Use shopt -sq expand_aliases, for example, this code in UTF-8 encoding:

#!/bin/bash

function запрещать() {
    if [ $1 -eq 3 ]
    then
        echo -n "Запрещено. Код ошибки: "
        echo `expr 2 \* 3 \* 47`
    else
        echo -n "."
        запрещать `expr $1 + 1`
    fi
}

#function запретить() {
#   запрещать 1
#}

shopt -sq expand_aliases
alias запретить='запрещать 1'

запретить
0
source your_script

instead of execute as a new shell, just source your script and alias will be accepted

mtk
  • 27,530
  • 35
  • 94
  • 130