Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I try to set a good Prompt in my bashrc and I need the value of $COLUMNS.
In many bashrc example in the web I saw this var used, but if I try to use it in my bashrc, it seems not to be set ... I don't know where I'm wrong ... how to get $COLUMNS set in bashrc ?
As far as I've been able to tell, you can't access the value of $COLUMNS directly from settings created in bashrc. This is probably because bashrc is used only for the shell's initial settings. You can however, create a separate script, and pass the value to it from the outside in the form of a command argument.
Back at the beginning of the year I posted a script I wrote that does pretty much the same thing as you want--it uses the $COLUMNS variable in setting the PS1 prompt. I'm sure you can adapt yours to use the same basic concept.
I'd like to see an example of that. Maybe there's some way to export the variable or something I don't know about.
Truthfully, I really don't know why it doesn't work. I wasn't able to figure it out when I was experimenting with it. Nothing I tried ever got me to get the variable value from within bashrc. It must have something to do with the way they're made (or not made) available to the shell or subshells or something.
Well, you piqued my curiosity again, so I've been spending some time playing around.
It seems that you CAN use the $COLUMNS variable inside of aliases and functions, and it will read the correct value every time.
But any time you try to read that value into a variable, including shell variables like PS1, it will always read as the value the terminal started at. It will not register the current value after changing the size. You can create a perfectly good function that properly echoes the value of $COLUMNS every time you run it, for example, but if you try to use that function to set the value of a variable inside bashrc, it fails. I suppose that it sets the variables at the time of parsing the file, and so the values become fixed.
I tried everything I can think of to get around this, using eval, indirect variable referencing, command substitution...nothing I try seems to affect it. I can find no way to make it re-set the variable value every time from within bashrc itself.
$ PROMPT_COMMAND='PS1="Number of columns: $(tput cols)__"'
Number of columns: 183__
Number of columns: 183__
Number of columns: 183__
Number of columns: 129__
Number of columns: 129__
Number of columns: 129__
Number of columns: 85__
Number of columns: 85__
Number of columns: 85__
D'oh! I just figured out what I was doing wrong, and it's something I had discovered
before and forgot. You have to use single quotes around the prompt value. That lets it set the value dynamically (I'm not sure why though. Probably it needs to parse the value each time or something).
I was only just reminded of it while looking over the code I wrote before.
But of course I was beaten to the punch. Just forget everything I said up to now.
D'oh! I just figured out what I was doing wrong, and it's something I had discovered
before and forgot. You have to use single quotes around the prompt value. That lets it set the value dynamically
It's the other way around. When you use single quotes no expansion is possible. That's why you need to use them, so the command is stored there instead of the interpreted value, which in turn allow it to change dynamically. The contents of PROMPT_COMMAND value is ran just before drawing each new prompt. So, with the lines I posted above:
Code:
PROMPT_COMMAND='PS1="Number of columns: $(tput cols)__"'
The contents of $PROMPT_COMMAND will be *exactly* this (and when I say "exactly" I mean exactly, including the quotation marks:
Code:
PS1="Number of columns: $(tput cols)__"
This command will be run each time a new prompt is to be drawn, which in turn makes your prompt dynamic. On the contrary if I had used this (double quotes):
Code:
PROMPT_COMMAND="PS1=\"Number of columns: $(tput cols)__\""
Then it wouldn't work, it will always use the original value. This is because when running that from bashrc expansion will take place (because double quotes don't prevent command nor variable expansion. Hence, the value stored in COMMAND_PROMPT will be this:
Code:
PS1="Number of columns: 183__"
You can try yourself in command line:
Code:
$ PROMPT_COMMAND='PS1="Number of columns: $(tput cols)__"'
Number of columns: 183__#<<- this is the initial value
Number of columns: 183__#<<- now I resize my terminal
Number of columns: 183__#
Number of columns: 152__#<<-as you see, the value changed
Number of columns: 152__#<<-this is the contents of PROMPT_COMMAND
Number of columns: 152__echo $PROMPT_COMMAND
PS1="Number of columns: $(tput cols)__"
Number of columns: 152__#<<-now I re-set it using double quotes instead
Number of columns: 152__PROMPT_COMMAND="PS1=\"Number of columns: $(tput cols)__\""
Number of columns: 152__#<<-and resize the terminal again
Number of columns: 152__
Number of columns: 152__#as you see, the value didn't change, now it's hardcoded
Number of columns: 152__echo $PROMPT_COMMAND
PS1="Number of columns: 152__"
To sum up, single quotes prevent expansion, so the command is run every time the prompt needs to be drawn. On the contrary, double quotes don't prevent command expansion, so it's evaluated once only, when bashrc is run.
It's the other way around. When you use single quotes no expansion is possible. That's why you need to use them, so the command is stored there instead of the interpreted value, which in turn allow it to change dynamically.
That's what I meant. I just didn't say it very well. I was trying to say that the string must be protected until it's time for the command to be actually run.
But I'm glad now that I've got everything cleared up. I see I was laboring under some misconceptions from my previous experiences. Now that I know what the hang-up was I've been able to move my previous script into a function inside bashrc and don't have to call a separate file anymore.
I've also spent some time spicing up my prompt with colors too. And just to help out anyone else trying the same thing, it took me a while before I discovered that you have to enclose the escape sequences in \[ and \] or else bash gets confused about newlines. Arch Linux has a really good wiki page about prompt customization that helped me out there.
That's what I meant. I just didn't say it very well. I was trying to say that the string must be protected until it's time for the command to be actually run.
Well, it's a bit hard to explain it in a clear way even if you know how it works. I don't think I did a particularly good job at explaining it either, I'd rather think that our posts complement each other so hopefully anyone reading them both in this context might understand how it truly works.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.