Or you can just…not quote the tilde. Folks always seem to reflexively quote “strings” in Bash while not realizing that (almost) everything is a string and most strings are not quoted and it would be odd to do it (e.g. no one is doing `"ls" "-a" "foo"`).
This feature, or at least the syntactic unit in question has a name here "bare words". You also have these in some contexts in Perl and Ruby, YAML, and probably some other languages, idk.
I've also seen this even with people who seem like generally competent shell users. Idrgi
Unless you're running a shell command from python. That was the first time I saw a command string broken down into "string" arguments for every thing like that.
Good decision and avoid the shell
whenever you can. Too late for me. I did my fair share of shell programming (and learned if from some real masters) so that my mind is already encumbered. My confidence in being able to write a longer or more complex shell script with 0 errors is still 0, so it gives me nothing.
While we're all getting pedantic and esoteric, in zsh you can do this:
path+=(~/.local/bin)
You don't even have to use the "export" keyword. Not that I would do this, but since we're all pointing out random shell stuff...
(In zsh the lowercase "path" variable is an array that's automatically tied to the $PATH string, so you can just add to it using parens to signify new array elements, separated by a space.)
Not necessarily about tildes but about some of the craziness that can happen with bash at large orgs:
At a past job, I was trying to figure out what part of my basrhc was setting a particular environment variable. I assumed that it must be some kind of default installed in my user profile and/or inheriting from /etc/<something>.
I realized pretty quickly that my bashrc was importing some other files. Again, the assumption was that this would be one file deep in the import.
It turned out there were 10+ layers of import starting from an "ur-bashrc" and then layer upon layer of more and more imports to finally get to a user level profile.
I was going to say “it always seems to work for me” then I saw “… actually works in Bash and Zsh, because …”.
Another Bash-ism I need to be careful not to use when trying to be portable.
It is worth noting that on a lot of systems /bin/sh isn't bash (or zsh) so if you want to rely on Bashisms (or just can't be bothered looking for them) be specific and use “#!/bin/bash” for you hashbang. On Debian and similar it is usually dash for instance.
For various embedded environments that use busybox it's busybox's brand of ash. I generally enjoy the opportunity to learn when bumping up against these kind of edge cases.
I wish Linux distros would ship a "Terminal"/"CLI" program etc that is decoupled from the scripting language. Have a universal Path env var that isn't tied to a specific shell. Lets you execute cd commands, launch python/git/cargo/arbitrary applications etc, and have a good bookmark + autocomplete system. It feels like the conflation of scripting language + CLI application is the root of these complications and subtleties.
If you are using shell scripting (And prefer Bash etc over Python), you would keep using Bash/Fish/Zsh etc. If you are using the CLI to launch applications that don't have a GUI, navigate directories and perform file system operations, then you would use the plain terminal.
It is a clear example of RTFM!
An expansion is no a variable. An expansion not expands under quotes.
A variable expansion is not simply an expansion as it is between brackets.
Again RTFM instead of wait for a miracle of your agent.
Ehh, there are many, many (documented) gotchas about commonly used software that routinely bite people. Yes, it would be great if everyone were an expert in how every aspect of their toolkit works, but that is not practical.
Just maybe, just maybe reserving somethings is not a bad idea... Whatever the fanatics say... There is enough features in shell that maybe banning somethings would be correct design.
I was expecting this article to be about skew between HOME environment variable and getpwent(3) (usually from /etc/passed) views of the home directory.
They can be different things. Suppose your user is foobar, ordinarily homed at /home/foobar. You can write HOME=/tmp/my-test-home. Then, ~/qux will become/tmp/my-test-home instead of the usual /home/foobar/qux. That's because bash and zsh use HOME to resolve ~.
Almost. If you write ~foobar/qux, you get /home/foobar/qux again because the ~-with-username syntax looks up the getpwent home directory not the environment one.
And of course language runtimes are all schizo about whether the "user home directory" API uses HOME or the getpwent database or whatever to determine the home directory.
It's a mess, TBH. It used to be useful to temporarily bind HOME to something else to do things like create isolated test environments. Now, because of the aforementioned schizo sprinkler of randomness in the environment, you're going to have a bad time if you don't keep HOME synced to getpwent home directory.
Afaik it's habit to give system paths precedence so a malicious script can't shadow e.g. sudo and steal your password, escalating a local file write into root
So many headaches could be avoided if we only allowed `[A-Za-z0-9._-]` in paths. (Arguably, even `-` can be problematic.) Encoding issues, expansion, parameter separation, ... and I never saw a convincing case in favor of supporting anything else.
I always joked about setting a custom keyboard layout to replace the space char with the underscore char specifically for avoiding spaces in file paths.
Or you can just…not quote the tilde. Folks always seem to reflexively quote “strings” in Bash while not realizing that (almost) everything is a string and most strings are not quoted and it would be odd to do it (e.g. no one is doing `"ls" "-a" "foo"`).
This feature, or at least the syntactic unit in question has a name here "bare words". You also have these in some contexts in Perl and Ruby, YAML, and probably some other languages, idk.
I've also seen this even with people who seem like generally competent shell users. Idrgi
I feel like this is common knowledge and should not be worth mentioning. But then it apparently is not common knowledge, as the article proves.
Have I run into this at some point?
I certainly have.
Have I learned to quote better and only where appropriate from it?
I certainly have.
Bourne compatible shells take a while to learn and require some experience. This won't change, but alternatives exist, with their own caveats.
Unless you're running a shell command from python. That was the first time I saw a command string broken down into "string" arguments for every thing like that.
People quote both too often and too little.
GENERAL RULE
1. Double-quote dollar sign expressions, and nothing else.
2. Single-quote words with a literal special character, and nothing else. ---I should point out that the author's example is NOT fixed by different quoting though.
Because tilde expansion only happens at the beginning of the word.Or just stop using bash. It’s a terrible language to write and has tons of footguns.
The trick is to quote explicitly and correctly. “ and ‘ are different.
You need to read the manual.
I think the appropriate method by POSIX rules would be:
I may be wrong. If I'm not, that works in any POSIX-compliant shell.Edit: this appears to work properly with mksh on my phone:
I never use tilde in scripts, only as a convenience when typing commands interactively.
$HOME otherwise, which still has gotchas but they are the same as any other environment variable.
Yeah, in scripts I try to be as explicit as possible. `$HOME` for the home directory, `$XDG_DATA_HOME` for `/home/foo/.local/share/`, etc.
The more specific you are, the less gotchas you're going to fall to.
I refuse to let knowledge about Calvinball-level grotesque rules about quoting and escaping in bash encumber my mind.
Good decision and avoid the shell whenever you can. Too late for me. I did my fair share of shell programming (and learned if from some real masters) so that my mind is already encumbered. My confidence in being able to write a longer or more complex shell script with 0 errors is still 0, so it gives me nothing.
Kind of seems like you should have noticed this by your ~/.local/bin PATH not working?
You can just do:
PATH is already exported. Quotes are also not necessary for assignments.Looks dangerous to put a user writable directory ahead of system directories in PATH
While we're all getting pedantic and esoteric, in zsh you can do this:
path+=(~/.local/bin)
You don't even have to use the "export" keyword. Not that I would do this, but since we're all pointing out random shell stuff...
(In zsh the lowercase "path" variable is an array that's automatically tied to the $PATH string, so you can just add to it using parens to signify new array elements, separated by a space.)
Not necessarily about tildes but about some of the craziness that can happen with bash at large orgs:
At a past job, I was trying to figure out what part of my basrhc was setting a particular environment variable. I assumed that it must be some kind of default installed in my user profile and/or inheriting from /etc/<something>.
I realized pretty quickly that my bashrc was importing some other files. Again, the assumption was that this would be one file deep in the import.
It turned out there were 10+ layers of import starting from an "ur-bashrc" and then layer upon layer of more and more imports to finally get to a user level profile.
It was so convoluted that I was going nuts until I found this Stack Exchange post: https://unix.stackexchange.com/questions/813/how-to-determin...
It turns on "tracing" for bash imports so that you can then narrow down on where the env variable is getting set.
I was going to say “it always seems to work for me” then I saw “… actually works in Bash and Zsh, because …”.
Another Bash-ism I need to be careful not to use when trying to be portable.
It is worth noting that on a lot of systems /bin/sh isn't bash (or zsh) so if you want to rely on Bashisms (or just can't be bothered looking for them) be specific and use “#!/bin/bash” for you hashbang. On Debian and similar it is usually dash for instance.
For various embedded environments that use busybox it's busybox's brand of ash. I generally enjoy the opportunity to learn when bumping up against these kind of edge cases.
I wish Linux distros would ship a "Terminal"/"CLI" program etc that is decoupled from the scripting language. Have a universal Path env var that isn't tied to a specific shell. Lets you execute cd commands, launch python/git/cargo/arbitrary applications etc, and have a good bookmark + autocomplete system. It feels like the conflation of scripting language + CLI application is the root of these complications and subtleties.
If you are using shell scripting (And prefer Bash etc over Python), you would keep using Bash/Fish/Zsh etc. If you are using the CLI to launch applications that don't have a GUI, navigate directories and perform file system operations, then you would use the plain terminal.
$PATH is not tied to any specific shell. And what you're describing is a shell, so I'm not sure how it's any different from existing solutions.
I always thought that there should be a proc style file system for simlinks to user specific data.
I'm not sure why this can't be done. Security people will have a million reasons, I guess it's possible one of them might be valid.
IIUC, you're describing an extremely restricted (some would say underpowered) shell.
It sounds like you could make it yourself in ~10 lines of Python or bash. I don't see it catching on, though.
Juste create a file ~ which is a symlink to home :)
Big brain time here
In every single directory you're ever going to have as cwd when running that software?
I expected it to also talk about ~username. See e.g.: echo ~root ~pulse ~sddm
It is a clear example of RTFM! An expansion is no a variable. An expansion not expands under quotes. A variable expansion is not simply an expansion as it is between brackets.
Again RTFM instead of wait for a miracle of your agent.
Ehh, there are many, many (documented) gotchas about commonly used software that routinely bite people. Yes, it would be great if everyone were an expert in how every aspect of their toolkit works, but that is not practical.
People only reading the manual after they shot themselves in the foot.
Hilarious!
Reminds me of early days of Cursor when it decided it would be a good idea to create a directory named "~" in my repo root!
That was a scary mistake to unwind!
Just maybe, just maybe reserving somethings is not a bad idea... Whatever the fanatics say... There is enough features in shell that maybe banning somethings would be correct design.
I was expecting this article to be about skew between HOME environment variable and getpwent(3) (usually from /etc/passed) views of the home directory.
They can be different things. Suppose your user is foobar, ordinarily homed at /home/foobar. You can write HOME=/tmp/my-test-home. Then, ~/qux will become/tmp/my-test-home instead of the usual /home/foobar/qux. That's because bash and zsh use HOME to resolve ~.
Almost. If you write ~foobar/qux, you get /home/foobar/qux again because the ~-with-username syntax looks up the getpwent home directory not the environment one.
And of course language runtimes are all schizo about whether the "user home directory" API uses HOME or the getpwent database or whatever to determine the home directory.
It's a mess, TBH. It used to be useful to temporarily bind HOME to something else to do things like create isolated test environments. Now, because of the aforementioned schizo sprinkler of randomness in the environment, you're going to have a bad time if you don't keep HOME synced to getpwent home directory.
the irony of the submitted url having a weird double slash // in it.
I should have read the docs before getting ~/ tattooed on my wrist.
If you haven’t quoted it, I think you’re fine.
Alternative title: There's no place like $HOME
bad example in the article:
better:Afaik it's habit to give system paths precedence so a malicious script can't shadow e.g. sudo and steal your password, escalating a local file write into root
Bash footgun #238503.
https://en.wikipedia.org/wiki/The_UNIX-HATERS_Handbook
That's standard POSIX.
Tilde expands when at the beginning of an unquoted word.
Pretty straightforward.
---Bash has a few extra.
well.. it's in zsh (and probably any other *sh) too
So many headaches could be avoided if we only allowed `[A-Za-z0-9._-]` in paths. (Arguably, even `-` can be problematic.) Encoding issues, expansion, parameter separation, ... and I never saw a convincing case in favor of supporting anything else.
What about people who do not speak English? or even use Latin letters?
If you're trying to avoid headaches then definitely don't allow -. At least not as the first character in a segment.
And allowing any letters from any language is probably worth the hassle.
I always joked about setting a custom keyboard layout to replace the space char with the underscore char specifically for avoiding spaces in file paths.