Search code examples
bashcommand-substitution

bash doesn't run commands in sequential order


I have a bash script that contains the following:

MY_COMMAND="MY_PWD=`pwd`; export MY_PWD; MY_PWD_BASENAME=`basename $MY_PWD`; echo $MY_PWD_BASENAME"; export MY_COMMAND

When I source the script from the terminal, I get the following error:

basename: missing operand
Try `basename --help' for more information.

This indicates that the commands in MY_COMMAND are not executed in sequential order. What is happening here?


Solution

  • The following line:

    MY_COMMAND="MY_PWD=`pwd`; export MY_PWD; MY_PWD_BASENAME=`basename $MY_PWD`; echo $MY_PWD_BASENAME"
    

    will not execute the following commands (as you may think):

    MY_PWD=`pwd`
    export MY_PWD
    MY_PWD_BASENAME=`basename $MY_PWD`
    echo $MY_PWD_BASENAME"
    

    Instead it will expand the command substitutions

    `pwd`
    `basename $MY_PWD`
    

    and replace them with their output. Since $MY_PWD is not set, basename will get executed without the required argument, like:

    basename
    

    That leads to the error.


    Fix: I recommend to use $() instead of backticks for the command substitution. One benefit is that you can nest them:

    MY_COMMAND="MY_PWD=$(pwd); export MY_PWD; MY_PWD_BASENAME=$(basename "$(pwd)"); echo $MY_PWD_BASENAME"
    

    However, that's just the syntax fix. Generally I recommend to use a function like @chepner suggested

    lib.sh

    function basename_pwd() {
        basename "$(pwd)"
    }
    

    Use the function:

    #!/bin/bash
    source "lib.sh"
    basename_pwd