Search code examples
bashscripting

What could be preventing my alias from expanding in a shell script


I am trying to set an alias in a script and then execute the alias later on in the script. I've verified that the file path that the alias contains is valid, and I've also set the shell script to expand aliases as well, yet the script still refuses to use the alias. What could I be doing incorrectly here?

Script:

#set location of parallel script and replace ~ with $HOME if necessary
parallellocation="~/newnnm/parallel"
parallellocation="${parallellocation/#\~/$HOME}"
#If the parallellocation variable is set and a parallel command is not currently available, 
#proceed with setting an alias that points to the parallellocation variable
if [ -r "$parallellocation" ] && ! command -v parallel &>/dev/null; then
        shopt -s expand_aliases
        alias parallel="$parallellocation"
        parallel
fi

Sample output:

./processlocations_new2.sh
./processlocations_new2.sh: line 98: parallel: command not found

Solution

  • As reflected in the comment record on the question, bash seems not to honor alias definitions or setting of the alias_expand option within the scope of an if block or other compound command. The Bash Manual explains this:

    The rules concerning the definition and use of aliases are somewhat confusing. Bash always reads at least one complete line of input before executing any of the commands on that line. Aliases are expanded when a command is read, not when it is executed. Therefore, an alias definition appearing on the same line as another command does not take effect until the next line of input is read. The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. Aliases are expanded when a function definition is read, not when the function is executed, because a function definition is itself a command. As a consequence, aliases defined in a function are not available until after that function is executed. To be safe, always put alias definitions on a separate line, and do not use alias in compound commands.

    (Emphasis added.) The comments do not refer directly to shell options, but the same logic that says alias definitions within a compound command do not apply within the same compound command also implies that it is the value of the expand_aliases option in effect when the compound command is read that applies.

    The question arose as to how to use a shell function instead of an alias for this purpose. Here's one way:

    altparallel="$HOME/newnnm/parallel"
    
    parallellocation=
    if command -v parallel >/dev/null 2>&1; then
      parallellocation="command parallel"
    elif [[ -x "$altparallel" ]]; then
      parallellocation="$altparallel"
    fi
    
    # Runs parallel with the given arguments.  Uses the 'parallel' command
    # found in the path if there is one, or a local one designated by
    # $altparallel if that exists and is executable.  Exit status is that of
    # 'parallel', or 1 if no 'parallel' command is available.
    parallel() {
      [[ -z "$parallellocation" ]] && return 1
    
      # expansion of $parallellocation is intentionally unquoted
      $parallellocation "$@"
    }
    

    You source that from your environment setup scripts to get a parallel function defined that does what you want.

    On the third hand, if all you want is a script that runs one version of parallel or the other, directly, then you don't need either a function or an alias. Just figure out which you want to run, and run it, something like:

    altparallel="$HOME/newnnm/parallel"
    
    if command -v parallel >/dev/null 2>&1; then
      parallel "$@"
    elif [[ -x "$altparallel" ]]; then
      "$altparallel" "$@"
    else
      exit 1
    fi