{"id":675,"date":"2015-02-01T21:59:17","date_gmt":"2015-02-02T02:59:17","guid":{"rendered":"http:\/\/jonesling.us\/blog\/?p=675"},"modified":"2015-02-01T22:37:40","modified_gmt":"2015-02-02T03:37:40","slug":"bash-prompt","status":"publish","type":"post","link":"https:\/\/blog.jonesling.us\/?p=675","title":{"rendered":"Bash Prompt"},"content":{"rendered":"<p>I think a person&#8217;s command-line prompt says a lot about them.\u00a0 Some people have big fancy prompts with tidbits of data; some people have simple black &amp; white prompts.\u00a0 Some people like fancy or frivolous things like <a title=\"Smiley &amp; Frowny bash prompt\" href=\"http:\/\/serverfault.com\/questions\/3743\/what-useful-things-can-one-add-to-ones-bashrc\/3816#3816\" target=\"_blank\">smiley and frowny faces based on the error status of the last command<\/a>; some people are strictly utilitarian.\u00a0 I mostly fall into the last category &#8211; I like some color with my prompts when possible, but otherwise I only want to see my name, server, cwd, and <abbr title=\"Version Control System\">VCS<\/abbr> branch (if any).<br \/>\n<!--more--><\/p>\n<h2 style=\"font-family: monospace;\">\/etc\/profile<\/h2>\n<pre style=\"font-size: 8px;\">...\nif [ -n \"${BASH_VERSION}\" ] ; then\n    # Newer bash ebuilds include \/etc\/bash\/bashrc which will setup PS1\n    # including color.  We leave out color here because not all\n    # terminals support it.\n    if [ -f \/etc\/bash\/bashrc ] ; then\n        # Bash login shells run only \/etc\/profile\n        # Bash non-login shells run only \/etc\/bash\/bashrc\n        # Since we want to run \/etc\/bash\/bashrc regardless, we source it \n        # from here.  It is unfortunate that there is no way to do \n        # this *after* the user's .bash_profile runs (without putting \n        # it in the user's dot-files), but it shouldn't make any \n        # difference.\n        . \/etc\/bash\/bashrc\n    else\n        PS1='\\u@\\h \\w \\$ '\n    fi\nelse\n    # Setup a bland default prompt.  Since this prompt should be useable\n    # on color and non-color terminals, as well as shells that don't\n    # understand sequences such as \\h, don't put anything special in it.\n    PS1=\"${USER:-$(whoami 2&gt;\/dev\/null)}@$(uname -n 2&gt;\/dev\/null) \\$ \"\nfi\n...\n<\/pre>\n<h2 style=\"font-family: monospace;\">~\/.bashrc<\/h2>\n<pre style=\"font-size: 8px;\">...\n# Load in the git branch prompt script, and alter PS1 to include the\n# current branch on the prompt\nsource ~\/.git-prompt\n\n# PS1 may include an extra space at the end, so trim it off so we can\n# include the altered prompt and a space\nPS1=${PS1\/% \/}'$(__git_ps1 \" (%s)\") '\n...\n<\/pre>\n<p>The code for <code>.git-prompt<\/code> is a little longer, and credit goes to <a href=\"mailto:spearce@spearce.org\" target=\"_blank\">Shawn O. Pearce<\/a>.\u00a0 There&#8217;s probably a more-compact version somewhere but this works well-enough for my needs.<\/p>\n<h2 style=\"font-family: monospace;\">~\/.git-prompt<\/h2>\n<pre style=\"font-size: 8px;\">\n# bash\/zsh git prompt support\n#\n# Copyright (C) 2006,2007 Shawn O. Pearce &lt;spearce@spearce.org&gt;\n# Distributed under the GNU General Public License, version 2.0.\n#\n# This script allows you to see the current branch in your prompt.\n#\n# To enable:\n#\n#    1) Copy this file to somewhere (e.g. ~\/.git-prompt.sh).\n#    2) Add the following line to your .bashrc\/.zshrc:\n#        source ~\/.git-prompt.sh\n#    3a) Change your PS1 to call __git_ps1 as\n#        command-substitution:\n#        Bash: PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ '\n#        ZSH:  PS1='[%n@%m %c$(__git_ps1 \" (%s)\")]\\$ '\n#        the optional argument will be used as format string.\n#    3b) Alternatively, if you are using bash, __git_ps1 can be\n#        used for PROMPT_COMMAND with two parameters, &lt;pre&gt; and\n#        &lt;post&gt;, which are strings you would put in $PS1 before\n#        and after the status string generated by the git-prompt\n#        machinery.  e.g.\n#           PROMPT_COMMAND='__git_ps1 \"\\u@\\h:\\w\" \"\\\\\\$ \"'\n#        will show username, at-sign, host, colon, cwd, then\n#        various status string, followed by dollar and SP, as\n#        your prompt.\n#        Optionally, you can supply a third argument with a printf\n#        format string to finetune the output of the branch status\n#\n# The argument to __git_ps1 will be displayed only if you are currently\n# in a git repository.  The %s token will be the name of the current\n# branch.\n#\n# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,\n# unstaged (*) and staged (+) changes will be shown next to the branch\n# name.  You can configure this per-repository with the\n# bash.showDirtyState variable, which defaults to true once\n# GIT_PS1_SHOWDIRTYSTATE is enabled.\n#\n# You can also see if currently something is stashed, by setting\n# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,\n# then a '$' will be shown next to the branch name.\n#\n# If you would like to see if there're untracked files, then you can set\n# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked\n# files, then a '%' will be shown next to the branch name.  You can\n# configure this per-repository with the bash.showUntrackedFiles\n# variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is\n# enabled.\n#\n# If you would like to see the difference between HEAD and its upstream,\n# set GIT_PS1_SHOWUPSTREAM=\"auto\".  A \"&lt;\" indicates you are behind, \"&gt;\"\n# indicates you are ahead, \"&lt;&gt;\" indicates you have diverged and \"=\"\n# indicates that there is no difference. You can further control\n# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list\n# of values:\n#\n#     verbose       show number of commits ahead\/behind (+\/-) upstream\n#     legacy        don't use the '--count' option available in recent\n#                   versions of git-rev-list\n#     git           always compare HEAD to @{upstream}\n#     svn           always compare HEAD to your SVN upstream\n#\n# By default, __git_ps1 will compare HEAD to your SVN upstream if it can\n# find one, or @{upstream} otherwise.  Once you have set\n# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by\n# setting the bash.showUpstream config variable.\n#\n# If you would like to see more information about the identity of\n# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE\n# to one of these values:\n#\n#     contains      relative to newer annotated tag (v1.6.3.2~35)\n#     branch        relative to newer tag or branch (master~4)\n#     describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)\n#     default       exactly matching tag\n#\n# If you would like a colored hint about the current dirty state, set\n# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on\n# the colored output of \"git status -sb\".\n\n# __gitdir accepts 0 or 1 arguments (i.e., location)\n# returns location of .git repo\n__gitdir ()\n{\n    # Note: this function is duplicated in git-completion.bash\n    # When updating it, make sure you update the other one to match.\n    if [ -z \"${1-}\" ]; then\n        if [ -n \"${__git_dir-}\" ]; then\n            echo \"$__git_dir\"\n        elif [ -n \"${GIT_DIR-}\" ]; then\n            test -d \"${GIT_DIR-}\" || return 1\n            echo \"$GIT_DIR\"\n        elif [ -d .git ]; then\n            echo .git\n        else\n            git rev-parse --git-dir 2&gt;\/dev\/null\n        fi\n    elif [ -d \"$1\/.git\" ]; then\n        echo \"$1\/.git\"\n    else\n        echo \"$1\"\n    fi\n}\n\n# stores the divergence from upstream in $p\n# used by GIT_PS1_SHOWUPSTREAM\n__git_ps1_show_upstream ()\n{\n    local key value\n    local svn_remote svn_url_pattern count n\n    local upstream=git legacy=\"\" verbose=\"\"\n\n    svn_remote=()\n    # get some config options from git-config\n    local output=\"$(git config -z --get-regexp '^(svn-remote\\..*\\.url|bash\\.showupstream)$' 2&gt;\/dev\/null | tr '\\0\\n' '\\n ')\"\n    while read -r key value; do\n        case \"$key\" in\n        bash.showupstream)\n            GIT_PS1_SHOWUPSTREAM=\"$value\"\n            if [[ -z \"${GIT_PS1_SHOWUPSTREAM}\" ]]; then\n                p=\"\"\n                return\n            fi\n            ;;\n        svn-remote.*.url)\n            svn_remote[ $((${#svn_remote[@]} + 1)) ]=\"$value\"\n            svn_url_pattern+=\"\\\\|$value\"\n            upstream=svn+git # default upstream is SVN if available, else git\n            ;;\n        esac\n    done &lt;&lt;&lt; \"$output\"\n\n    # parse configuration values\n    for option in ${GIT_PS1_SHOWUPSTREAM}; do\n        case \"$option\" in\n        git|svn) upstream=\"$option\" ;;\n        verbose) verbose=1 ;;\n        legacy)  legacy=1  ;;\n        esac\n    done\n\n    # Find our upstream\n    case \"$upstream\" in\n    git)    upstream=\"@{upstream}\" ;;\n    svn*)\n        # get the upstream from the \"git-svn-id: ...\" in a commit message\n        # (git-svn uses essentially the same procedure internally)\n        local svn_upstream=($(git log --first-parent -1 \\\n                    --grep=\"^git-svn-id: \\(${svn_url_pattern#??}\\)\" 2&gt;\/dev\/null))\n        if [[ 0 -ne ${#svn_upstream[@]} ]]; then\n            svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}\n            svn_upstream=${svn_upstream%@*}\n            local n_stop=\"${#svn_remote[@]}\"\n            for ((n=1; n &lt;= n_stop; n++)); do\n                svn_upstream=${svn_upstream#${svn_remote[$n]}}\n            done\n\n            if [[ -z \"$svn_upstream\" ]]; then\n                # default branch name for checkouts with no layout:\n                upstream=${GIT_SVN_ID:-git-svn}\n            else\n                upstream=${svn_upstream#\/}\n            fi\n        elif [[ \"svn+git\" = \"$upstream\" ]]; then\n            upstream=\"@{upstream}\"\n        fi\n        ;;\n    esac\n\n    # Find how many commits we are ahead\/behind our upstream\n    if [[ -z \"$legacy\" ]]; then\n        count=\"$(git rev-list --count --left-right \\\n                \"$upstream\"...HEAD 2&gt;\/dev\/null)\"\n    else\n        # produce equivalent output to --count for older versions of git\n        local commits\n        if commits=\"$(git rev-list --left-right \"$upstream\"...HEAD 2&gt;\/dev\/null)\"\n        then\n            local commit behind=0 ahead=0\n            for commit in $commits\n            do\n                case \"$commit\" in\n                \"&lt;\"*) ((behind++)) ;;\n                *)    ((ahead++))  ;;\n                esac\n            done\n            count=\"$behind  $ahead\"\n        else\n            count=\"\"\n        fi\n    fi\n\n    # calculate the result\n    if [[ -z \"$verbose\" ]]; then\n        case \"$count\" in\n        \"\") # no upstream\n            p=\"\" ;;\n        \"0  0\") # equal to upstream\n            p=\"=\" ;;\n        \"0  \"*) # ahead of upstream\n            p=\"&gt;\" ;;\n        *\"  0\") # behind upstream\n            p=\"&lt;\" ;;\n        *)      # diverged from upstream\n            p=\"&lt;&gt;\" ;;\n        esac\n    else\n        case \"$count\" in\n        \"\") # no upstream\n            p=\"\" ;;\n        \"0  0\") # equal to upstream\n            p=\" u=\" ;;\n        \"0  \"*) # ahead of upstream\n            p=\" u+${count#0 }\" ;;\n        *\"  0\") # behind upstream\n            p=\" u-${count%  0}\" ;;\n        *)      # diverged from upstream\n            p=\" u+${count#* }-${count%  *}\" ;;\n        esac\n    fi\n\n}\n\n\n# __git_ps1 accepts 0 or 1 arguments (i.e., format string)\n# when called from PS1 using command substitution\n# in this mode it prints text to add to bash PS1 prompt (includes branch name)\n#\n# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc)\n# in that case it _sets_ PS1. The arguments are parts of a PS1 string.\n# when two arguments are given, the first is prepended and the second appended\n# to the state string when assigned to PS1.\n# The optional third parameter will be used as printf format string to further\n# customize the output of the git-status string.\n# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true\n__git_ps1 ()\n{\n    local pcmode=no\n    local detached=no\n    local ps1pc_start='\\u@\\h:\\w '\n    local ps1pc_end='\\$ '\n    local printf_format=' (%s)'\n\n    case \"$#\" in\n        2|3)    pcmode=yes\n            ps1pc_start=\"$1\"\n            ps1pc_end=\"$2\"\n            printf_format=\"${3:-$printf_format}\"\n        ;;\n        0|1)    printf_format=\"${1:-$printf_format}\"\n        ;;\n        *)  return\n        ;;\n    esac\n\n    local g=\"$(__gitdir)\"\n    if [ -z \"$g\" ]; then\n        if [ $pcmode = yes ]; then\n            #In PC mode PS1 always needs to be set\n            PS1=\"$ps1pc_start$ps1pc_end\"\n        fi\n    else\n        local r=\"\"\n        local b=\"\"\n        if [ -f \"$g\/rebase-merge\/interactive\" ]; then\n            r=\"|REBASE-i\"\n            b=\"$(cat \"$g\/rebase-merge\/head-name\")\"\n        elif [ -d \"$g\/rebase-merge\" ]; then\n            r=\"|REBASE-m\"\n            b=\"$(cat \"$g\/rebase-merge\/head-name\")\"\n        else\n            if [ -d \"$g\/rebase-apply\" ]; then\n                if [ -f \"$g\/rebase-apply\/rebasing\" ]; then\n                    r=\"|REBASE\"\n                elif [ -f \"$g\/rebase-apply\/applying\" ]; then\n                    r=\"|AM\"\n                else\n                    r=\"|AM\/REBASE\"\n                fi\n            elif [ -f \"$g\/MERGE_HEAD\" ]; then\n                r=\"|MERGING\"\n            elif [ -f \"$g\/CHERRY_PICK_HEAD\" ]; then\n                r=\"|CHERRY-PICKING\"\n            elif [ -f \"$g\/BISECT_LOG\" ]; then\n                r=\"|BISECTING\"\n            fi\n\n            b=\"$(git symbolic-ref HEAD 2&gt;\/dev\/null)\" || {\n                detached=yes\n                b=\"$(\n                case \"${GIT_PS1_DESCRIBE_STYLE-}\" in\n                (contains)\n                    git describe --contains HEAD ;;\n                (branch)\n                    git describe --contains --all HEAD ;;\n                (describe)\n                    git describe HEAD ;;\n                (* | default)\n                    git describe --tags --exact-match HEAD ;;\n                esac 2&gt;\/dev\/null)\" ||\n\n                b=\"$(cut -c1-7 \"$g\/HEAD\" 2&gt;\/dev\/null)...\" ||\n                b=\"unknown\"\n                b=\"($b)\"\n            }\n        fi\n\n        local w=\"\"\n        local i=\"\"\n        local s=\"\"\n        local u=\"\"\n        local c=\"\"\n        local p=\"\"\n\n        if [ \"true\" = \"$(git rev-parse --is-inside-git-dir 2&gt;\/dev\/null)\" ]; then\n            if [ \"true\" = \"$(git rev-parse --is-bare-repository 2&gt;\/dev\/null)\" ]; then\n                c=\"BARE:\"\n            else\n                b=\"GIT_DIR!\"\n            fi\n        elif [ \"true\" = \"$(git rev-parse --is-inside-work-tree 2&gt;\/dev\/null)\" ]; then\n            if [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" ] &&\n               [ \"$(git config --bool bash.showDirtyState)\" != \"false\" ]\n            then\n                git diff --no-ext-diff --quiet --exit-code || w=\"*\"\n                if git rev-parse --quiet --verify HEAD &gt;\/dev\/null; then\n                    git diff-index --cached --quiet HEAD -- || i=\"+\"\n                else\n                    i=\"#\"\n                fi\n            fi\n            if [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n                git rev-parse --verify refs\/stash &gt;\/dev\/null 2&gt;&1 && s=\"$\"\n            fi\n\n            if [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ] &&\n               [ \"$(git config --bool bash.showUntrackedFiles)\" != \"false\" ] &&\n               [ -n \"$(git ls-files --others --exclude-standard)\" ]\n            then\n                u=\"%\"\n            fi\n\n            if [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n                __git_ps1_show_upstream\n            fi\n        fi\n\n        local f=\"$w$i$s$u\"\n        if [ $pcmode = yes ]; then\n            local gitstring=\n            if [ -n \"${GIT_PS1_SHOWCOLORHINTS-}\" ]; then\n                local c_red='\\e[31m'\n                local c_green='\\e[32m'\n                local c_lblue='\\e[1;34m'\n                local c_clear='\\e[0m'\n                local bad_color=$c_red\n                local ok_color=$c_green\n                local branch_color=\"$c_clear\"\n                local flags_color=\"$c_lblue\"\n                local branchstring=\"$c${b##refs\/heads\/}\"\n\n                if [ $detached = no ]; then\n                    branch_color=\"$ok_color\"\n                else\n                    branch_color=\"$bad_color\"\n                fi\n\n                # Setting gitstring directly with \\[ and \\] around colors\n                # is necessary to prevent wrapping issues!\n                gitstring=\"\\[$branch_color\\]$branchstring\\[$c_clear\\]\"\n\n                if [ -n \"$w$i$s$u$r$p\" ]; then\n                    gitstring=\"$gitstring \"\n                fi\n                if [ \"$w\" = \"*\" ]; then\n                    gitstring=\"$gitstring\\[$bad_color\\]$w\"\n                fi\n                if [ -n \"$i\" ]; then\n                    gitstring=\"$gitstring\\[$ok_color\\]$i\"\n                fi\n                if [ -n \"$s\" ]; then\n                    gitstring=\"$gitstring\\[$flags_color\\]$s\"\n                fi\n                if [ -n \"$u\" ]; then\n                    gitstring=\"$gitstring\\[$bad_color\\]$u\"\n                fi\n                gitstring=\"$gitstring\\[$c_clear\\]$r$p\"\n            else\n                gitstring=\"$c${b##refs\/heads\/}${f:+ $f}$r$p\"\n            fi\n            gitstring=$(printf -- \"$printf_format\" \"$gitstring\")\n            PS1=\"$ps1pc_start$gitstring$ps1pc_end\"\n        else\n            # NO color option unless in PROMPT_COMMAND mode\n            printf -- \"$printf_format\" \"$c${b##refs\/heads\/}${f:+ $f}$r$p\"\n        fi\n    fi\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I think a person&#8217;s command-line prompt says a lot about them.\u00a0 Some people have big fancy prompts with tidbits of data; some people have simple black &amp; white prompts.\u00a0 Some people like fancy or frivolous things like smiley and frowny faces based on the error status of the last command; some people are strictly utilitarian.\u00a0 &hellip; <a href=\"https:\/\/blog.jonesling.us\/?p=675\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Bash Prompt&#8221;<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","wprm-recipe-roundup-name":"","wprm-recipe-roundup-description":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[9],"tags":[84,85,83],"class_list":["post-675","post","type-post","status-publish","format-standard","hentry","category-linux","tag-bash","tag-bashrc","tag-linux"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":false,"jetpack_shortlink":"https:\/\/wp.me\/p4o3FW-aT","jetpack-related-posts":[],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=\/wp\/v2\/posts\/675","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=675"}],"version-history":[{"count":15,"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=\/wp\/v2\/posts\/675\/revisions"}],"predecessor-version":[{"id":690,"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=\/wp\/v2\/posts\/675\/revisions\/690"}],"wp:attachment":[{"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=675"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=675"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jonesling.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=675"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}