Why doesn't my Bash script recognize aliases?

  • In my ~/.bashrc file reside two definitions:

    1. commandA, which is an alias to a longer path
    2. commandB, which is an alias to a Bash script

    I want to process the same file with these two commands, so I wrote the following Bash script:


    #!/bin/bash
    
    for file in "[email protected]"
        do
        commandA $file
        commandB $file
    done
    

    Even after logging out of my session and logging back in, Bash prompts me with command not found errors for both commands when I run this script.

    What am I doing wrong?

    BTW, there's no need to log in and out to have an alias recognized. You need just do `source ~/.bashrc`.

    For my case I was connected by SSH agent remotely, after adding alias as I closed the SSH agent and connected again it started working.

    An alias is a way of shortening a command. (They are only used in interactive shells and not in scripts — this is one of the very few differences between a script and an interactive shell.)

  • Correct answer

    10 years ago

    First of all, as ddeimeke said, aliases by default are not expanded in non-interactive shells.

    Second, .bashrc is not read by non-interactive shells unless you set the BASH_ENV environment variable.

    But most importantly: don't do that! Please? One day you will move that script somewhere where the necessary aliases are not set and it will break again.

    Instead set and use variables as shortcuts in your script:

    #!/bin/bash
    
    CMDA=/path/to/gizmo
    CMDB=/path/to/huzzah.sh
    
    for file in "[email protected]"
    do
        $CMDA "$file"
        $CMDB "$file"
    done
    

    That solution doesn’t work for the usual `alias` use cases. E.g. `alias mv="mv -v --backup=numbered"`.

    @Evi1M4chine: Yes, it does. At least after I reverted Gilles unnecessary edit. But it might be better to use a different variable for the parameters, anyway.

    Ah, note the *lack* of quotes around `$CMDA` / `$CMDB`… Apart from uppercase variables being reserved for bash itself in bash, and it indeed working, that lack of quotes makes me really uneasy… Thanks anyway.

    @Evi1M4chine: Uh, what? 1. I removed the quotes myself in the most recent edit. 2. where do you get the "reserved for bash itself" from? this would be the first I've heard of it. 3. If _that_ makes you uneasy, how do you feel about using bash in the first place? Anyway, use a separate variable for the options as I told you.

    1. From experience, unquoted variables have the bad habit of blowing up in one’s face. E.g. when the variable is empty, one expects it to have no spaces but it does, etc. Here, the latter is intended, but it still makes me uneasy. :) 2. Turns out it’s something in-between: http://wiki.bash-hackers.org/scripting/style#syntax_and_coding_guidelines → If you use uppercase variables, there’s a chance that a later version of bash uses that name itself, breaking your script. 3. Don’t worry. You seem to have mistaken my comment for criticism. It wasn’t. :)

    How about `CMDA="$(which gizmo)"`?

    @alvas: the assumption is that `gizmo` is not on the path or there is a command with the same name but a higher priority. else you could simple set `CMDA` to plain `gizmo` in the first place.

    @Evi1M4chine The lowercase rule applies for local and script variables. In contrast, environment variables are typically uppercase. Prefix should be enough to prevent collision since this is what everyone has been doing: Bundler is using `BUNDLE_`, OpenSSH is using `SSH_`. If you can't survive the prefix way, you are probably exposing too many environment variables (so you are doomed anyway).

    I'm not convinced with the reasoning that script can break when it is moved. The same can happen if path is set by environment variable. The path to command may change when script is moved to a different environment. Or command may not be installed in new environment. So, when script moves, user will have to take care of environment changes anyway. No?

    @rineez: except this way it's _right there in the script_

    It's a drop-in replacement. What is the correct way without duplicating every script for use with that drop-in replacement?

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM