1

So I found a cool bash prompt from this reddit thread: https://www.reddit.com/r/archlinux/comments/5vusvx/here_is_my_bash_prompt_whats_your_favorite/

The one I was testing out was the top comment by @khordes. Here is what is expected: https://i.stack.imgur.com/917bh.jpg

However, I get something a little different. Here is where the issue is:

───[~]───[ 33 files, 2334400]

As you can see there is quite a lot of space before the number of files. The actual code is here:

PS1="┌─[\`if [ \$? = 0 ]; then echo \[\e[32m\]✔\[\e[0m\]; else echo \[\e[31m\]✘\[\e[0m\]; fi\`]───[\[\e[01;49;39m\]\u\[\e[00m\]\[\e[01;49;39m\]@\H\[\e[00m\]]───[\[\e[1;49;34m\]\W\[\e[0m\]]───[\[\e[1;49;39m\]\$(ls | wc -l) files, \$(ls -lah | grep -m 1 total | sed 's/total //')\[\e[0m\]]\n└───▶ "

Any input on how to fix that would be greatly appreciated.

L. Norman
  • 483
  • 7
  • 21
  • 1
    Do you *really* want all that performance overhead every time you print a prompt? That command isn't cheap. – Charles Duffy Apr 18 '18 at 17:07
  • 1
    Anyhow, `$(ls | wc -l)` does indeed have whitespace. I suppose to continue the trend of awfulness, you could just make it `$(ls | wc -l | tr -d '[[:space:]]')` – Charles Duffy Apr 18 '18 at 17:08
  • I guess not, but I am just curious as to why it is not working correctly. – L. Norman Apr 18 '18 at 17:08
  • Run `ls | wc -l` and look at its output. That'll answer your curiosity. – Charles Duffy Apr 18 '18 at 17:08
  • BTW, see [BashFAQ #4](https://mywiki.wooledge.org/BashFAQ/004) for better practice in counting files. – Charles Duffy Apr 18 '18 at 17:09
  • Awesome, that fixed it and answered my question. Thanks for your help! – L. Norman Apr 18 '18 at 17:10
  • 1
    (Also, see the APPLICATION USAGE and RATIONALE sections in http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html to grok why using backslash-escape sequences in `echo` is a bad idea; `printf` is the preferred replacement, which will behave consistently across all POSIX-compliant shells). – Charles Duffy Apr 18 '18 at 17:10
  • 1
    ...btw, if you want to only do more expensive operations on changing directories, rather than every time a prompt is printed, consider following the pattern given in the answers to https://stackoverflow.com/questions/49882286/conditional-pwd-in-an-ps1-definition/49882606#49882606 – Charles Duffy Apr 18 '18 at 17:13
  • Oh thats cool! I will check it out. I not very good with bash, but I appreciate all the helpful resources. – L. Norman Apr 18 '18 at 17:16
  • 1
    `PROMPT_COMMAND=set_prompt; set_prompt () { PS=; ...; PS1+="┌─[$status]───[$userhost]───[$dir]───[$file_info]\n" PS1+="└───▶"; }`, with `...` being the code that sets the four variables that contribute to your prompt, makes it a lot easier to understand how your prompt is built and to modify it later. – chepner Apr 18 '18 at 17:32

1 Answers1

1

This prompt uses $(ls | wc -l) to list files in the current directory.

On GNU platforms, wc -l has no preceding whitespace when not passed any filenames.

On BSD platforms (such as MacOS), the number is prefixed with spaces.

Thus, the author of this prompt presumably tested it on a Linux variant or other GNU platform, and I'm presuming that you're running MacOS or another BSD. To be consistent, you need to ensure that such space is removed -- or switch to a mechanism for listing files that doesn't depend on wc, such as that given in BashFAQ #4.

One alternative is the following:

$(shopt -s nullglob; set -- *; echo "$#")
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • This fixes the whitespace issue but does not show how many files are located in the directory. The comments on my original post answered my question. – L. Norman Apr 18 '18 at 17:23
  • Which part does not show how many files are located in the directory? The `shopt -s nullglob; set -- *; echo "$#"` approach certainly does show the number of entries in the current directory (setting the argument list within the subshell created to do the command substitution to the entries in the current directory, then displaying the number of items on said list). – Charles Duffy Apr 18 '18 at 17:26
  • Hmm. I inserted this instead of the above and found it showing 0 files. Was this supposed to be appended to the above? – L. Norman Apr 18 '18 at 17:28
  • I'm guessing it wasn't escaped to prevent evaluation at assignment time. The above is how it's supposed to come out in the PS4 -- if you're assigning it in double quotes (which you shouldn't), some backslashes are needed. – Charles Duffy Apr 18 '18 at 17:29
  • ...but better is to fix the quoting context done for the whole assignment so you don't need all those backslashes in the first place, and can just use `$(...)` instead of `\$(...)`, and `$#` instead of `\$#`. – Charles Duffy Apr 18 '18 at 17:30
  • 1
    (To be clear, change from `"..."` to `'...'` to make `$`s no longer special). – Charles Duffy Apr 18 '18 at 17:31
  • Single quotes did not fix it, however a backslash did. Thanks! – L. Norman Apr 18 '18 at 17:34
  • @L.Norman, I promise you, single quotes do fix it. Try `PS1='$(shopt -s nullglob; set -- *; echo "$#")'` on its own. If you're putting those single quotes *inside* double quotes, OTOH, then they're data rather than syntax; you need to end the double-quoted string before you can start a single-quoted string. – Charles Duffy Apr 18 '18 at 17:37
  • @L.Norman, ...that is to say, `PS1="...whatever..."'...whatever...'"...whatever..."` has the first and third `whatever`s parsed with double-quoting rules, and the one in the middle parsed with single-quoting rules. – Charles Duffy Apr 18 '18 at 17:40
  • Ahh, I misunderstood what you were saying. That worked. – L. Norman Apr 18 '18 at 17:42