What does ~ stand for in a bash command line? - bash

I know that ~ usually denotes my home directory. But I just accidentally issued
touch ~
and got a list of I don't know what:
~admin ~Debian-exim/ ~gnats ~messagebus/ ~postfix/ ~saned ~systemd-network/ ~xrdp etc...
What is this list? What does ~ stand for in this context?

Take a look at the man page for bash. There you will find a section called Tilde Expansion:
If a word begins with an unquoted tilde character (`~'), all of the characters preceding the first unquoted slash (or all characters, if there
is no unquoted slash) are considered a tilde-prefix. If none of the characters in the tilde-prefix are quoted, the characters in the tilde-pre‐
fix following the tilde are treated as a possible login name.
So you probably got all your possible login names.

Related

Change directory to subfolder with single quotes and exclamation mark

I'm trying to navigate down to a subfolder in a bash shell. The name of the subfolder is:
Let's Go Play!
I cannot figure out how to escape the single quote (apostrophe) or the exclamation point.
I have tried
cd "Let's Go Play\!"
cd "Let\'s Go Play\!"
Thanks.
The correct form is
cd "Let's Go Play!"
Inside double quotes, backslashes are not special unless they come before a newline, a quote, a backslash, a dollar sign or a backtick. Backslash-newline is removed altogether; a backslash followed by one of the other four characters in that list is removed and the character loses its special significance.
Inside single quotes, backslashes are never removed and have no special significance. Consequently, it is impossible to insert a single quote into a single-quoted string and so there is no single-quoted form of the above cd command. However, you can concatenate words, so you could write:
cd 'Let'"'"'s Go Play!'
Outside of quoted words, backslashes are more general. A backslash followed by any character other than a newline character is removed from the input and the following character becomes an ordinary character (even if it were ordinary already). Backslash-newline is removed entirely from the input, so that there is no way to insert a newline character into an unquoted string.
So you could have written:
cd Let\'s\ Go\ Play\!
But the double-quoted version one seems simpler.
Exclamations points are an extension to the Posix standard (the above rules comes directly from the Posix standard), and the bash implementation is a bit quirky and sometimes really annoying. Exclamation points introduce history expansion, unless they are inside single quotes, are preceded by a backslash, or are followed by whitespace or either an equals sign or (if shell option extglob is enabled) an open parenthesis. Inside double quotes, an exclamation point is also not special just before the closing quote. (You can change the history expansion character to something other than an exclamation point so technically I should write "the history expansion character".)
Even though a backslash makes an exclamation mark unspecial, the backslash is not removed from the input stream unless it would have been removed by the Posix rules. So the exclamation point in
echo "a\!b"
is an ordinary character (it is preceded by a backslash), but the backslash is also an ordinary character (it is not followed by one of the characters in the double-quote list), so the result is
a\!b
(Although I copied those rules from the bash manual, I know there are some other cases where history expansion is suppressed, such as when the exclamation point is part of a parameter expansion such as $! or ${!name}. And I think there are more of these exceptions that I can't remember off-hand.)
I find all that so annoying, and I rely so little on history expansion, that I simply turn it off by adding set +H to my bash startup file ~/.bashrc. If you turn history expansion off, then exclamation points lose all special significance. However, there are people who seem to really like history expansion, and if you're one of them, more power to you.

Can't use folder path with tilde in rmdir

I need to be able to remove a directory that is relative to the Documents folder of any user's system.
rmdir: ~/Documents/Folder: No such file or directory
If I manually enter the expanded path (/Users/ricky/Documents/Folder), it works fine.
I thought bash automatically expanded the tilde at the beginning of paths?
Update:
After trying a bunch of different approaches as recommended, I'm pretty confident now that the issue is with how I'm storing the path. I'm getting the path from a text file which I read line by line:
...
export_folder_path="$(echo $line | cut -f2 -d=)"
...
echo $export_folder_path
rmdir $export_folder_path
rmdir "$HOME/Documents/Folder\ 1"
This outputs the following:
$HOME/Documents/Folder\ 1
rmdir: $HOME/Documents/Folder\ 1: No such file or directory
rmdir: /Users/ricky/Documents/Folder\ 1: Directory not empty (This is actually what I want)
I can't work out what the difference between my manually typing the export path and using the variable. Why is the variable refusing to expand $HOME? I have tried many variations of adding quotations with no luck.
Tilde expansion doesn't work in all cases. You can instead use the HOME variable:
rmdir $HOME/Documents/Folder
From bash manual:
Tilde Expansion If a word begins with an unquoted tilde character
('~'), all of the characters preceding the first unquoted slash (or
all characters, if there is no unquoted slash) are considered a
tilde-prefix. If none of the characters in the tilde-prefix are
quoted, the characters in the tilde-prefix following the tilde are
treated as a possible login name. If this login name is the null
string, the tilde is replaced with the value of the shell parameter
HOME. If HOME is unset, the home directory of the user executing the
shell is substituted instead. Otherwise, the tilde-prefix is
replaced with the home directory associated with the specified login
name.
If the tilde-prefix is a '~+', the value of the shell variable PWD
replaces the tilde-prefix. If the tilde-prefix is a '~-', the value
of the shell variable OLDPWD, if it is set, is substituted. If the
characters following the tilde in the tilde-prefix consist of a
number N, optionally prefixed by a '+' or a '-', the tilde-prefix is
replaced with the corresponding element from the directory st, as it
would be displayed by the dirs builtin invoked with the tilde- prefix
as an argument. If the characters following the tilde in the
tilde-prefix consist of a number without a leading '+' or '-', '+' is
assumed.
If the login name is invalid, or the tilde expansion fails, the word
is unchanged.

Bash escaping/expanding order

I'm fairly new to Bash and I'm having trouble working out what is happening to my input as it is interpreted. Specifically, when escaping occurs relative to the other expansion steps.
From what I've read, bash does the following (in order):
brace expansion
tilde expansion
parameter and variable expansion
command substitution
arithmetic expansion
word splitting
filename expansion
But this list doesn't include when it converts all escape sequences e.g. '\\' into their meanings e.g. '\'. That is, if I want to print a backslash character. The command to run is
echo \\
not
echo \
So the syntax required for the semantics of a backslash character is two backslashes. This must be converted into a single slash representation internally.
It seems to be sometime before command substitution as I found out with a small test program.
So, my question is: When does this step take place? (or a complete list of the bash interpretation loop would be perfect)
and also, are there any other subtleties in the interpreter that are likely to catch me out? (related to knowing the complete list i guess)
From the man page's Expansion section, just before the Redirection section.
Quote Removal
After the preceding expansions, all unquoted occurrences of the characters \, ', and " that did not result from one of the above expansions
are removed.
Quote removal is one final process after the seven expansions you list.

What does the path "//" mean?

I just found the direcory // on my machine and now i am wondering what it means.
user#dev:~$ cd /
user#dev:/$ pwd
/
user#dev:/$ cd //
user#dev://$ pwd
//
It is obvously the root directory, but when and why do i use the double slash instead of the single slash?
Is it related to the escaped path strings which i use while programming?
For example:
string path = "//home//user//foo.file"
I also tried it with zsh but it changes to the usual root directory /. So I think its bash specific.
This is part of the specification for Pathname Resolution:
A pathname consisting of a single <slash> shall resolve to the root directory of the process. A null pathname shall not be successfully resolved. If a pathname begins with two successive <slash> characters, the first component following the leading <slash> characters may be interpreted in an implementation-defined manner, although more than two leading <slash> characters shall be treated as a single <slash> character.
So your shell is just following the specification and leaving // alone as it might be implementationally defined as something other than /.

When does the slash in a Linux path need to be outside quotes in a bash script

Why does the first expansion not work, yet the second does?
I know tilde has to be expanded outside quotes but the slash also had to be outside, unexpectedly.
#!/bin/bash
ls ~"/Documents/bashscripts/test.sh"
ls ~/"Documents/bashscripts/test.sh"
This is a subtlety in how tilde expansion works. In the second case, the tilde-followed-by-slash is expanded to the home directory of the current user. In the first case, the tilde-followed-by-quoted-word is attempted to be expanded to the home directory of the user named "/Documents/bashscripts/test.sh". From the manpage, Tilde Expansion section:
…all of the characters preceding the first unquoted slash are considered a tilde-prefix. If none of the characters in the tilde-prefix are quoted, the characters in the tilde-prefix following the tilde are treated as a possible login name. …

Resources