0

I have the following function in my .bash_profile:

function GIT_BRANCH() {

    STATUS="\$(git status 2> /dev/null)";

    if [[ ! ${STATUS} ]]; then
            if [[ ! ${STATUS} = *"working tree clean"* ]]; then
                    echo "not clean repo";
            else
                    echo "clean repo";
            fi
    else
            echo "not a repo";
    fi

}

If i run the command like this:

echo $(git status 2> /dev/null);
echo $(pwd);

then the command is unfortunately not executed in the same directory in which I am currently in the shell.

I tried to solve the problem as in the following example.

STATUS="\$(git status 2> /dev/null)";

This works fine as long as I output the variable with echo. If I understand this correctly, only the string is stored in the variable and the command is not executed when comparing. How do I get the return value of the command stored in STATUS and run the command in the same shell anyway?

EDIT:

I use the function in PS1. If i try:

function GIT_BRANCH() {
    STATUS="\$(git status 2> /dev/null)";
    echo ${STATUS};
    TEST="\$(pwd)";
    echo ${TEST};
}

export PS1="$(COLOR "199")\u$RESET_ALL$(COLOR "45") \h \w$RESET_ALL $(COLOR "199")$(GIT_BRANCH $DIRE)$RESET_ALL\n$(COLOR "199")$ >$RESET_ALL "

Then all works fine and i get the current directory. But thats don't work if i try to use this information in the function itself, like in the examples I've posted before.

Thanks for you help.

  • 1
    The command is executed in the same directory. What makes you think it isn't? Why did you write STATUS="\$(git status 2> /dev/null)", which sets STATUS to the string $(git status 2> /dev/null), and not STATUS="$(git status 2> /dev/null)", which sets STATUS to the output of git status, and is AFAICT what you need to make the function work (except that you should use git's porcelain commands do avoid parsing output meant for humans)? – Gilles Jul 10 '18 at 11:42
  • Unfortunately this doesn't seem to be the case when I try it with echo $(pwd), no matter which directory I'm in, it will always output the same. – AuroraCore Jul 10 '18 at 11:47
  • This should not happen. You may have something weird in your configuration but I can't think of what would cause this. What's the output when you run this? cd /; set -x; cd /tmp; pwd; echo $(pwd); set +x – Gilles Jul 10 '18 at 11:52
  • If i write the same script in a file like test.sh and run this file in the terminal all works normal. For example: #!/bin/bash STATUS=$(git status 2> /dev/null); echo ${STATUS}; The STATUS variable has the correct output as value. But i use the function in PS1, then the function run the git command not in the same directory that I'm currently in. – AuroraCore Jul 10 '18 at 11:58
  • 1
    You function is evaluated exactly once, when you set PS1 and then never again. Use single quotes rather than double quotes when assigning the value to PS1. – Kusalananda Jul 10 '18 at 13:00
2

Your issue is with quoting.

You are essentially setting your PS1 variable like

PS1="$(myfunction)"

(exporting PS1 is not needed as it's the current shell that's using it, only).

This will call myfunction at the time of assigning to PS1, and the function will never be called again.

Instead, you should use

PS1='$(myfunction)'

This would cause myfunction to be called each time the prompt is being displayed.

No special quoting is needed in the function itself.


Your function:

function GIT_BRANCH() {

    STATUS="\$(git status 2> /dev/null)";

    if [[ ! ${STATUS} ]]; then
            if [[ ! ${STATUS} = *"working tree clean"* ]]; then
                    echo "not clean repo";
            else
                    echo "clean repo";
            fi
    else
            echo "not a repo";
    fi

}

This could be rewritten as

GIT_BRANCH () {
    local status="$( git status --porcelain 2>&1 )"

    case "$status" in
        *"fatal: not a git repository"*)
            echo 'Not a repo' ;;
        "")
            echo 'Clean repo' ;;
        *)
            echo 'Not clean repo' ;;
    esac
}

Or, using if statements:

GIT_BRANCH () {
    local status="$( git status --porcelain 2>&1 )"

    if [[ "$status" == *"fatal: not a git repository"* ]]; then
        echo 'Not a repo'
    elif [[ -z "$status" ]]; then
        echo 'Clean repo'
    else
        echo 'Not clean repo'
    fi
}
0

Use the PROMPT_COMMAND parameter

alux@deb904:~$ PROMPT_COMMAND=pwd
/home/alux
alux@deb904:~$ cd /tmp
/tmp
alux@deb904:/tmp$

With your function :

$ PROMPT_COMMAND=GIT_BRANCH
  • That would run before displaying each new prompt, but it would not place the output in the prompt. – Kusalananda Jul 10 '18 at 14:58
0

The parameter PS1 is a static string, which can be customized by inserting a number of backslash-escaped special characters (\u, \d, \$, ...). Only these tags are dynamic.

alux@deb904:~$ echo $PS1
\u@\h:\w\$
alux@deb904:~$ ps1="$PS1"

when PS1 is valuated with a command (PS1=$(pwd) or PS1=`pwd`), PS1 is valued with the return of this command.

alux@deb904:~$ PS1="$(pwd) > "
/home/alux > echo $PS1
/home/alux >
/home/alux > cd /tmp
/home/alux > echo $PS1
/home/alux >
/home/alux > pwd
/tmp

The PROMPT_COMMAND parameter can be validated to contain a command line executed before the value of PS1 is displayed. We use a function, it is more appropriate.

/home/alux > PS1=$ps1
alux@deb904:~$ myprompt(){ pwd; echo " > "; }
alux@deb904:~$ COMMAND_PROMPT=myprompt
/home/alux
>
alux@deb904:~$

To avoid going back to the line, use echo -n.

/home/alux
>
alux@deb904:~$ myprompt(){ echo -n "$(pwd) > "; }
/home/alux > alux@deb904:~$ cd /tmp
/tmp > alux@deb904:/tmp$

We can delete the value of PS1.

/tmp > alux@deb904:/tmp$PS1=
/tmp >

But we do not have special characters escaped from the backslash.

/tmp >  myprompt(){ echo -n "$(pwd) \u \h  > "; }
/tmp \u \h >

Then we can use other parameter ($USER, $HOSTNAME, ...)

/tmp \u \h >  myprompt(){ echo -n "$(pwd) $USER $HOSTNAME  > "; }
/tmp alux deb906 >

The value of PROMPT_COMMAND is executed before the display of the PS1 value. So we can use PROMPT_COMMAND to modify PS1.

/tmp alux deb906  > myprompt(){ PS1=$(echo -n "$(pwd) (\h) > "); }
/tmp (deb904) > echo $PS1
/tmp (deb904) >
/tmp (deb904) > cd ~
/home/alux (deb904) > echo $PS1
/home/alux (deb904) >
/home/alux (deb904) > PROMPT_COMMAND=
/home/alux (deb904) > PS1=$ps1
alux@deb904:~$ 

Now in your .bash_profile :

function GIT_BRANCH() {
  local status="$(git status 2> /dev/null)"
  local msg
  if [ "${status}" ]; then
        if [ ! "${status}" = *"working tree clean"* ]; then
                msg="not clean repo"
        else
                msg="clean repo"
        fi
  else
        msg="not a repo"
  fi
  PS1="\u \h \w ${msg}\n\$ "
}
PROMPT_COMMAND=GIT_BRANCH
-1

Use eval :

function GIT_BRANCH() {

  STATUS="\$(git status 2> /dev/null)";

  if [ "$(eval echo ${STATUS})" ]; then

        if [ ! $(eval echo ${STATUS}) = *"working tree clean"* ]; then
                echo "not clean repo";
        else
                echo "clean repo";
        fi
  else
        echo "not a repo";
  fi

}

Or another additional function :

function STATUS(){
  git status 2> /dev/null
}
function GIT_BRANCH() {
  if [ "$(STATUS)" ]; then
    …
  fi
}
  • If i create a new function: function GET_PWD() { pwd } then i have the same problem. No matter in which directory I am, the value is always the path of the user directory, in this directory is the .bash_profile. – AuroraCore Jul 10 '18 at 12:46
  • When my STATUS variable contains the string like STATUS="\$(git status 2> /dev/null)"; and i echo the value, only then i get the informations from right directory currently. – AuroraCore Jul 10 '18 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.