A subshell happens when a shell fork()s a child process, and that child process does not exec() anything (source).
For more gory details about fork
, exec
, processes and subshells, read below.
The following commands create subshells:
unset -v a; a=1 (echo "in the subshell, a is $a.") sh -c 'echo "in the child shell, a is $a."'
in the subshell, a is 1. in the child shell, a is .
fork
, exec
, processes and subshells :https://tldp.org/LDP/abs/html/subshells.html https://www.gnu.org/software/bash/manual/bash.html#Command-Execution-Environment https://unix.stackexchange.com/questions/264169/on-fork-children-processes-and-subshells/264199#264199 - you're in a console (i.e. shell) and type : [command][ENTER] - 'fork' makes a new process, with a new PID, that starts running in parallel from exactly where this one left off - 'exec' replaces the currently-executing code with a new program loaded from somewhere, running from the beginning ==> if this "new program" is the same binary (e.g. /bin/bash), there is nothing to 'exec' so, when you spawn a new program : - you first 'fork' yourself - then 'exec' that program in the child That is the fundamental theory of processes that applies everywhere, inside and outside of shells. Subshells are forks, and every non-builtin command you run leads to both a 'fork' and an 'exec'. https://unix.stackexchange.com/questions/264169/on-fork-children-processes-and-subshells/264192#264192 'fork', assuming all goes well, returns twice : - one return is in the parent process (which has the original process ID) - and the other in the new child process (a different process ID but otherwise sharing much in common with the parent process). At this point, the child could 'exec' something, which would cause some "new" binary to be loaded into that process, though the child need not do that, and could run other code already loaded via the parent process (zsh functions, for example). Hence, a fork may or may not result in a "completely new" process, if "completely new" is taken to mean something loaded via an 'exec' system call. details on fork + exec https://en.wikipedia.org/wiki/Fork%E2%80%93exec
What Happens in Vegas, Stays in Vegas.
#!/usr/bin/env bash a=3 displayA() { local message=$1 echo -e "a = $a\t$message" } main() { displayA 'in main, just started' let "a+=1" displayA 'in main, after increment' { let "a+=1" displayA 'in curly braces, after increment within braces' } displayA 'back in main' ( let "a+=1" displayA 'in parentheses, after increment within parentheses' ) displayA 'back in main' { let "a+=1" displayA 'increment + display as a background process' } & wait displayA 'back in main' } main
a = 3 in main, just started a = 4 in main, after increment a = 5 in curly braces, after increment within braces a = 5 back in main a = 6 in parentheses, after increment within parentheses a = 5 back in main a = 6 increment + display as a background process a = 5 back in main
myCommand myFile
myCommand aProcessDisguisedAsAFile
command1 <(command2)
: the output of command2 serves as input to command1command1 >(command2)
: the output of command1 serves as input to command2\n
is appended[space]
between the option and its value : tail -n 5 someFile=
between the option and its value : tail --lines=5 someFile --
(i.e. [space]
+--
+[space]
) marks the end of options, everything after this is an argument (even though it looks like a valid option)-
The title of this article : "system variables" is intended as a generic term meaning both the environment variables and the shell variables
There's a subtle difference between them, which is mostly a matter of scope (source) :
\\!\\!
"' history)
#!/usr/bin/env bash tmpScript=$(mktemp tmpScript.XXXXXXXX) cat << 'EOF' > "$tmpScript" #!/usr/bin/env bash main() { echo $# : $@; } main "$@" EOF chmod +x "$tmpScript" ./"$tmpScript" ./"$tmpScript" foo ./"$tmpScript" foo bar ./"$tmpScript" 'foo bar' rm "$tmpScript"
0 : 1 : foo 2 : foo bar 1 : foo bar
$*
and $@
hold a
b
c
d
(4 distinct elements)"$*"
holds a b c d
(a single string having spaces). This is not iterable because of the explicit double-quotes."$@"
holds a
b
c d
(the 3 script parameters). The double quotes protect spaces when they are part of the parameter itself.#!/usr/bin/env bash # run : ./script.sh a b 'c d' echo -e '\nwith $* :' for i in $*; do echo $i; done echo -e '\nwith $@ :' for i in $@; do echo $i; done echo -e '\nwith "$*" :' for i in "$*"; do echo $i; done echo -e '\nwith "$@" :' for i in "$@"; do echo $i; done
with $* : a b c d with $@ : a b c d with "$*" : a b c d with "$@" : a b c d
$n
, with n > 0when, on the CLI, you have ./myScript.sh foo bar baz |
these are arguments |
within the script, they turn into :
|
these are positional parameters |
"$@"
.$_
(tldp.org, gnu.org)(empty line) no argument used when assigning a value to a variable, nothing to echo hello this is the last argument of echo > , even if there are some extra directives on the command line ./test this refers to "$testFile" passed to rm : the value has been substituted
${BASH_SOURCE[0]} |
$0 |
---|---|
|
|
#!/usr/bin/env bash echo -e " \$0:$0 \$BASH_SOURCE:$BASH_SOURCE \${BASH_SOURCE[0]}:${BASH_SOURCE[O]} " | column -s ':' -t
$0 ./test.sh $BASH_SOURCE ./test.sh ${BASH_SOURCE[0]} ./test.sh
$0 /bin/bash $BASH_SOURCE test.sh ${BASH_SOURCE[0]} test.sh
https_proxy
and ftp_proxy
.
~whatever
(source) :
~bob
— the tilde expression is expanded into Bob's home directory
~
is expanded into $HOME
[space][tab][newline]
"SPACE
s ?LANG
(1, 2, 3)LC_COLLATE
, LC_NUMERIC, LC_TIME
, ) is provided; it doesn't override any setting, it provides the base value.LANGUAGE
LANGUAGE=en find charlie find: 'charlie': No such file or directory LANGUAGE=fr find charlie find: 'charlie': Aucun fichier ou dossier de ce type
:
)-separated list, to append a new value :
0
.
0 0 1 0 1 1 0
0 0 1 0 1 1 0
currentDir=$(pwd)
is double work since PWD
is already available.$[]
construct : this is an old syntax that has been obsoleted by $(())
12321
$(whoami)
in scripts
This variable is often set as an environment variable by Bash login startup files, but it is not actually a Bash builtin (source).
TERM
environment variable is not / improperly set.So, if you just want to use an exclamation mark (not followed by a space) in a string, just simple-quote it :
ALT | CTRL | |
---|---|---|
a | move to the beginning of the line | |
c | send the SIGINT signal to stop the current process | |
d | delete everything after the cursor | exits the current shell |
e | move to the end of the line | |
l | clear the screen | |
q | resume from CTRL-s | |
r | search history of commands | |
s | pause output to the screen. Useful when running a verbose command :
for i in {1..1000}; do echo $i; sleep 0.1; done
|
|
x-x | Jump back and forth between the cursor position and the beginning of the line | |
z | send the SIGTSTP signal to the current foreground process to send it to the background. Use fg to bring it back to the foreground. | |
_ | Undo the last keystroke. Can be repeated to undo several keys back | |
. | paste the last argument of the previous command. Repeat to cycle back in previous commands |
I like bananas. bananas are great. bananas are what I prefer. My favorite fruit is bananas.
I like bananas. bananas are great. oranges are what I prefer. My favorite fruit is bananas.
oranges are what I prefer.
I like bananas. bananas are great. oranges are what I prefer. My favorite fruit is bananas.
echo -e "$testString" | sed -r '/prefer/ s/bananas/oranges/'
I like bananas. bananas are great. oranges are what I prefer. My favorite fruit is bananas.
testFile='./testFile'; echo -e "$testString" > "$testFile"; echo 'BEFORE :'; cat "$testFile"; sed -i '/prefer/ s/bananas/oranges/' "$testFile"; echo -e '\nAFTER :'; cat "$testFile"; rm "$testFile"
BEFORE : I like bananas. bananas are great. bananas are what I prefer. My favorite fruit is bananas. AFTER : I like bananas. bananas are great. oranges are what I prefer. My favorite fruit is bananas.
At first sight, sed looked simpler to me than Awk, but Awk is also able to work on a specific field of every line, or on a specific field of a specific line.
#
and the rest of the line —if any\
: preserve the literal value of the following character (except newline)''
: preserve the literal value of each character enclosed within the quotes. A single quote may not occur between single quotes, even when preceded by a \
.""
: preserve the literal value of all characters enclosed within the quotes, except for $
, ``
and \
.*
within quotes.
{}
~
$myVariable
is substituted with its value$((arithmeticExpression))
is substituted with its resultSPACE
(actually, each character of $IFS
is a delimiter).*
, ?
or[
, it is considered as a pattern and replaced with an alphabetically sorted list of file names matching the pattern (if any. Otherwise, leave the special character as-is)Quoting shell variables is mandatory to protect scripts from unexpected effects should unquoted variables contain SPACE
characters (or any other character considered by the shell as a word separator, such as TAB
or NEWLINE
. Read more about IFS). Indeed, the SPACE
character is one of the common argument separators for the shell. Here come the quotes (but they must be set wisely ).
Let's play !
file my
my file
file my
file1 file2 my
file1 file2 my
ls: cannot access my file*: No such file or directory
my file1 my file2
ls: cannot access my: No such file or directory ls: cannot access file*: No such file or directory
*
inside double quotes
ls: cannot access my file*: No such file or directory
*
outside double quotes
my file1 my file2
ls $fileName*
ls "$fileName*"
$fileName
is recognized as a variable and will be substituted[SPACE]
between my
and file
can not be used to split : ls "my file*"*
is taken literally, nothing to expand. No file named exactly my file* (i.e. having a *
in the file name) found, so no change : ls "my file*"ls "$fileName"*
$fileName
is recognized as a variable and will be substitutedOn UTF-8-capable systems (and generally speaking : extended charsets), characters lists such as a-z
include special characters like à
, é
or î
. Thus, characters lists (a-z
) can not be used in regular expressions to discriminate ASCII/non-ASCII characters. To do so, the solution is to build a complete list of all characters to match against with a regular expression : abcdefghijklmnopqrstuvwxyz
(source).
if
statement in Bash and in Ksh while the tested variable is actually unset :
Shell | Output | |
---|---|---|
if [ ${undefinedVariable} -eq 0 ]; then echo 'this is the "THEN" part'; else echo 'this is the "ELSE" part'; fi |
||
Bash | -bash: [: -eq: unary operator expected this is the "ELSE" part |
|
Ksh | ksh: [: argument expected this is the "ELSE" part |
|
if [ ${undefinedVariable} -ne 0 ]; then echo ''this is the "THEN" part'; else echo ''this is the "ELSE" part'; fi |
||
Bash | -bash: [: -ne: unary operator expected this is the "ELSE" part |
|
Ksh | ksh: [: argument expected this is the "ELSE" part |
We note that :
-eq
or a -ne
test is made, the else
part is executed.ssh bob@sshServer << EOC command1 command2 EOC
|
:cat << EOL | grep base Roses are #ff0000 Violets are #0000ff All my base are belong to you EOL
cat << EOF > newFile.txt some text, line 1 some text, line 2 some text, line n EOF
cat << EOF > newFile.txt line 1, not indented line 2, space-indented line 3, TAB-indented EOF cat newFile.txt; rm newFile.txt
$(command)
into the result of executing command)$((1+1))
into 2)cat << EOF current user : $USER today : $(date +"%a %b %d") 2 apples + 1 banana is $((2+1)) fruits EOF
current user : stuart today : Fri Nov 17 2 apples + 1 banana is 3 fruits
cat << 'EOF' simple quotes : $USER today : $(date +"%a %b %d") 2 apples + 1 banana is $((2+1)) fruits EOF
simple quotes : $USER today : $(date +"%a %b %d") 2 apples + 1 banana is $((2+1)) fruits
-
) -prefixed stop token (source) :This is a cosmetic hack improving readability of scripts since its allows indenting the heredocs too. The -
in the stop token suppresses leading tabs in the output.
spaces
, including the line of the stop token itself which must be TAB
-indented. If space
-indented, the stop token line becomes invisible which causes an error :
./myScript.sh: line 63: warning: here-document at line 23 delimited by end-of-file (wanted `EOF') ./myScript.sh: line 64: syntax error: unexpected end of file
<<
and -
TAB
characters are stripped out and both versions seem to produce the same outputcat << EOF indent : none indent : SPACE * 2 indent : TAB * 1 EOF cat <<-EOF indent : none indent : SPACE * 2 indent : TAB * 1 EOF
indent : none indent : SPACE * 2 indent : TAB * 1 indent : none indent : SPACE * 2 indent : TAB * 1
value=42; exampleFile='/tmp/myExampleFile.txt'; cat << EOF > "$exampleFile"
if (\$something > $value)
blah
if (\$anything < ($value/2))
pooh
else
nomnom
if (true || false || whatever)
who_cares
EOF
cat "$exampleFile"; rm "$exampleFile"
outputs :
if ($something > 42) blah if ($anything < (42/2)) pooh else nomnom if (true || false || whatever) who_cares
cat << EOSQL | sqlplus -s / as sysdba | grep -Ev '^$' SELECT DISTINCT(TRUNC(last_refresh)) FROM dba_snapshot_refresh_times; query1; query2; EOSQLOr even :
echo -e "query1;\nquery2;" | sqlplus -s / as sysdba | grep -Ev '^$'But it is simpler to do :
sqlplus -s / as sysdba << EOSQL | grep -Ev '^$' query1; query2; EOSQLRemember :
HEADER data line 1 data line 2 data line 3You can retrieve all lines except the header ...
echo -e "HEADER\ndata line 1\ndata line 2\ndata line 3" | grep -v 'HEADER'
echo -e "HEADER\ndata line 1\ndata line 2\ndata line 3" | sed -n '2,$ p'
echo -e "HEADER\ndata line 1\ndata line 2\ndata line 3" | sed 1d
echo -e "HEADER\ndata line 1\ndata line 2\ndata line 3" | tail -n +2
for i in {1..1000}; do echo $RANDOM >> data.txt; done
sed can do it :
sed -r 's/(^.{3}).*$/\1/g' data.txtBut it's overkill as cut can do it way easier :
cut -c -3 data.txt
user@host $ emacs & vlc & [1] 10367 [2] 10368Here, emacs is the 1st command we've launched, 1 is its jobId and 10367 is its PID.
[1]- Running emacs & [2]+ Running vlc &
[1]- 10367 Running emacs & [2]+ 10368 Running vlc &
Field Value | Description | Example |
---|---|---|
[n] | Job ID
|
|
+ or - |
|
|
10367 | PID | |
Job status :
|
The %jobId syntax used to refer to a job is also known as jobspec.
Syntax | Description | Example |
---|---|---|
{value1,value2,value_n} |
String generation Generate as many strings as the number of parameters, including a prefix and/or a suffix |
echo foo{1,2,3}bar foo1bar foo2bar foo3bar |
|
Generate a string for each parameter from the specified interval, including a prefix and/or a suffix
|
echo test_{1..2}{a..b}_
test_1a_ test_1b_ test_2a_ test_2b_ echo {a..z..7}
a h o vmore examples |
${parameter:-default} |
Use default value If parameter is unset or null, default (which may be an expansion) is substituted. Otherwise, the value of parameter is substituted.
This can be used to make some function parameters optional (by giving them a default value when omitted) :
myFunction() { local myVariable=$1 local myOtherVariable=${2:-42} } |
key='value'; echo ${key:-'nothing'}; unset key; echo ${key:-'nothing'}
value nothing key='value'; default=42; echo ${key:-$default}; unset key; echo ${key:-$default}
value 42 |
${parameter:=default} |
Assign default value If parameter is unset or null, default (which may be an expansion) is assigned to parameter. The value of parameter is then substituted.
|
key='value'; result=${key:='nothing'}; echo $key; unset key; result=${key:='nothing'}; echo $key
value nothing |
${parameter:+value} |
Use value if parameter exists
If parameter exists, substitute (e.g. return) value (which may be an expansion).Otherwise (parameter is null or unset), return nothing. |
key='value'; echo ${key:+'key exists'}; unset key; echo ${key:+'key exists'}
key exists (empty line) |
${parameter?message} |
Return parameter, or display message if unset |
value=42; echo ${value?this variable is unset.}; unset value; echo ${value?this variable is unset.}
42 bash: value: this variable is unset. |
${parameter:offset:length} |
Substring Expansion
The last character of a string : ${parameter:(-1):1}
|
|
${#myString} |
String length
length of the string myString
Some documents/websites may state that
${#myArray} represents the number of items in the array myArray. This is wrong / obsolete (maybe it worked —with warnings— in previous Bash versions).(details) Looks like this works fine with multi-byte characters
|
myString='foo bar'; echo ${#myString}
7 a=$(echo -e '\u2639\u263a'); echo -e "$a\t${#a}"
☹☺ 2 |
${parameter#pattern} |
Remove pattern from the beginning of parameter
The pattern is matched against the beginning of parameter. The result is the expanded value of parameter with the shortest match deleted.
This can be used to retrieve the extension of a file name.
|
myString='abcdef'; echo ${myString#abc}; echo ${myString#[abc]}; myString='aaabbbccc'; echo ${myString#a*b}
def bcdef bbccc name=file.txt; echo ${name#*.}
txt |
${parameter##pattern} |
As above, but the longest match is deleted.
This can be used to retrieve the current directory name.
|
myString='aaabbbccc'; echo ${myString##a*b}
ccc log |
${parameter%pattern} |
Remove pattern from the end of parameter
The pattern is matched against the end of parameter. The result is the expanded value of parameter with the shortest match deleted.
This can be used to :
|
myString='aaabbbccc'; echo ${myString%a*b}; echo ${myString%b*c}
aaabbbccc aaabb |
${parameter%%pattern} |
As above, but the longest match is deleted. | |
${parameter/search/replace} |
In parameter, replace the 1st match of search with replace. |
myString='abcd abcd'; echo ${myString/cd/CD}
abCD abcd |
${parameter//search/replace} |
As above, but every match of search is replaced. |
myString='abcd abcd'; echo ${myString//cd/CD}
abCD abCD |
|
Return parameter with :
|
myString='hello, world'; echo ${myString^}; echo ${myString^^}; myString=${myString^^}; echo ${myString,}; echo ${myString,,}
Hello, world HELLO, WORLD hELLO, WORLD hello, world |
Code | Meaning |
---|---|
0 | success (aka " UNIX_SUCCESS " in my scripts) |
1 | catchall for general errors (aka " UNIX_FAILURE " in my scripts) |
2 | misuse of shell builtins |
124 | specific case with timeout |
126 | command invoked cannot execute |
127 | command not found |
128 | invalid argument to exit |
128 + n | fatal error signal n |
130 | script terminated by CTRL-c |
255* | exit status out of range |
Bits | Meaning |
---|---|
15-8 | shell command (child process) exit code |
7 | =1 if a core dump was produced |
6-0 | signal number that killed the process |
127
32512%255
127
$ apt-get install package
$ sudo !!
ls: cannot access '/rome': No such file or directory
Ooops
ls /home lost+found bob kevin stuart
HISTCONTROL=ignoredups
HISTCONTROL=ignorespace
HISTCONTROL=ignoreboth
HISTCONTROL=ignoredups:ignorespace
HISTCONTROL value is a colon (:
) -separated list.
export PS1='\u@\h:\w[\j]\$ '
Flag | Usage |
---|---|
\u | userName |
\h | hostname (up to first .) |
\w | current working directory |
\j | number of shell children jobs |
NOCOLOR="\[\e[0m\]" RED="\[\e[1;31m\]" GREEN="\[\e[0;32m\]" YELLOW="\[\e[1;33m\]" BLUE="\[\e[1;34m\]" SQUARE="\342\226\210" export PS1="\`if [ \$? = 0 ]; then echo '${GREEN}'; else echo '${RED}'; fi\`$SQUARE $RED\u$NOCOLOR@$BLUE\h $NOCOLOR[$YELLOW\j$NOCOLOR] \w\$ "
NOCOLOR="\[\e[0m\]" RED="\[\e[1;31m\]" GREEN="\[\e[0;32m\]" YELLOW="\[\e[1;33m\]" BLUE="\[\e[1;34m\]" SQUARE="\342\226\210" export PS1="\`if [ \$? = 0 ]; then echo '${GREEN}'; else echo '${RED}'; fi\`$SQUARE $RED\u$NOCOLOR@$BLUE\h $NOCOLOR[$YELLOW\j$NOCOLOR]\`git branch &>/dev/null; if [ \$? ]; then git branch 2>/dev/null | awk '/^\*/ {print \"[$BLUE\"\$2\"$NOCOLOR]\"}'; fi\` \w\$ "
\$
is an actual $
displayed as part of the prompt$PS1
requires to embed code, so that it is executed again each time $PS1
is displayed. Variables defined outside of the prompt definition actually are constants.$(...)
construct rather than `...`
for process substitution NOCOLOR="\[\e[0m\]" RED="\[\e[1;31m\]" GREEN="\[\e[0;32m\]" YELLOW="\[\e[1;33m\]" BLUE="\[\e[1;34m\]" SQUARE="\342\226\210" PROMPT_COMMAND='[ $? = 0 ] && squareColor="$GREEN" || squareColor="$RED"; \ currentGitBranch=$(git branch 2>/dev/null | awk '"'"'/^\*/ {print $2}'"'"'); \ [ -n "$currentGitBranch" ] && displayBranch="[$BLUE$currentGitBranch$NOCOLOR]" || displayBranch=''; \ PS1="$squareColor$SQUARE $RED\u$NOCOLOR@$BLUE\h $NOCOLOR[$YELLOW\j$NOCOLOR]$displayBranch \w\$ "'
NOCOLOR="\[\e[0m\]" RED="\[\e[1;31m\]" GREEN="\[\e[0;32m\]" brightGreen="\[\e[1;32m\]" YELLOW="\[\e[1;33m\]" BLUE="\[\e[1;34m\]" lightPurple="\[\e[1;35m\]" SQUARE="\342\226\210" PROMPT_COMMAND='[ $? = 0 ] && squareColor="$GREEN" || squareColor="$RED"; \ [ -z "$VIRTUAL_ENV" ] && displayVirtualEnv='' || displayVirtualEnv="($brightGreen$(basename "$VIRTUAL_ENV")$NOCOLOR) " currentGitBranch=$(git branch 2>/dev/null | awk '"'"'/^\*/ {print $2}'"'"'); \ [ -n "$currentGitBranch" ] && displayBranch="[$lightPurple$currentGitBranch$NOCOLOR]" || displayBranch=''; \ PS1="$displayVirtualEnv$squareColor$SQUARE $RED\u$NOCOLOR@$BLUE\h $NOCOLOR[$YELLOW\j$NOCOLOR]$displayBranch \w\$ "'
$VIRTUAL_ENV
is defined in virtualenvironmentBaseDir/bin/activate0;xx
= dark, 1;xx
= lightBlack 0;30 White 1;37 Dark Gray 1;30 Light Gray 0;37 Red 0;31 Light Red 1;31 Green 0;32 Light Green 1;32 Brown 0;33 Yellow 1;33 Blue 0;34 Light Blue 1;34 Purple 0;35 Light Purple 1;35 Cyan 0;36 Light Cyan 1;36
Bash has a built-in pattern matching parser (which must not be mistaken with actual regular expressions). Wildcards can be used with any command that accepts file names as arguments (i.e. almost anything ).
When receiving a command :.
is NOT a wildcard in Bash.Wildcard | replaced by |
---|---|
~ | the path to the home directory of the current user
Within quotes, the
~ character is NOT substituted. Check :
echo ~ '~' "~"
/home/bob ~ ~
use $HOME instead
|
? | any single character |
* | any sequence of characters (including the empty string) |
[abcde] [a-e] [!abcde] [!a-e] |
exactly one character from the list : abcde (see examples below) exactly one character from the range : "a" to "e" any single character that is not listed : abcde any single character that is not within the range : "a" to "e" |
{foo,bar} | exactly one entire word in the options given |
`myCommand` | anything between the backticks must be considered as a command
Even though this works fine, it is now old-fashioned, and the $(myCommand) construct should be preferred.
|
regular expression | match | corresponding Bash pattern |
---|---|---|
x? |
0 or 1 occurrence of x (i.e. optional x) | ?(x) |
x+ |
1 or more occurrences of x | +(x) |
x* |
0 or more occurrences of x | *(x) |
[^x] |
anything but x | !(x) |
touch /tmp/myFile_{foo,bar,baz} ls /tmp/myFile* | grep -E 'ba[rz]'; ls /tmp/myFile*[rz] ls /tmp/myFile* | grep -E 'o+'; ls /tmp/myFile*+(o) ls /tmp/myFile* | grep -E '[^o]$'; ls /tmp/myFile*!(o) <-- ko :-( ls /tmp/myFile* | grep -E '[^o].$'; ls -1 /tmp/myFile??!(o)? rm /tmp/myFile_{foo,bar,baz}
Command with a wildcard | Returns |
---|---|
ls * echo * |
all non-hidden files from the current directory |
ls *n echo *n |
all non-hidden files which name ends with a n |
ls *n* | all non-hidden files which name contains a n, even as the last character |
ls *.* | all non-hidden files which name contains a ., even as the last character, but NOT as the first character as this would be an hidden file |
ls *foo* | all non-hidden files which name contains foo, or just displays ls : can not access *foo* : no file or directory of this type if no such file exists |
echo *foo* | all non-hidden files which name contains foo, or just displays *foo* if no such file exists (no wildcard substitution made before "echoing") |
ls ?[ae]* | all non-hidden files which name contains either a a or a e as the 2nd character |
touch foo[123]; ls | foo[123] : no matching file found, so no substitution possible : Bash took it literally |
echo BEFORE; touch foo1 foo2 foo3; ls; echo AFTER; rm foo[123]; ls | BEFORE foo1 foo2 foo3 AFTER (void)files matching the wildcard exist, so Bash made the corresponding substitutions before running rm |
Shell type | Technical definition | Description | Use case |
---|---|---|---|
login |
|
This is a shell that is opened after authenticating, either locally (e.g. at boot time) or via SSH : the prompt is displayed after a successful login (going through /bin/login). The login shell is the first process that executes under your user ID when you log in for an interactive session. |
|
non-login | The prompt is displayed without re-authenticating. | shell emulator within a GUI :
|
|
interactive |
|
The shell : |
|
non-interactive | A non-interactive shell is usually present when a shell script is running. It is non-interactive because it is processing a script and not waiting for user input between commands. For these shell invocations, only the environment inherited from the parent shell is used. |
|
export http_proxy="http://kevin:password@proxyHost:port/" export https_proxy="http://kevin:password@proxyHost:port/"
Upon user login, the OS starts a shell. Bourne shells read commands from ~/.profile when invoked as the login shell. Bash (which is a Bourne shell) reads commands from ~/.bash_profile when invoked as the login shell. If ~/.bash_profile doesn't exist, it reads from ~/.profile instead.
A shell launched at any other time (terminal emulator within GUI environment, or through a SSH connection) :
Therefore :
if [ -r ~/.profile ]; then . ~/.profile; fi case "$-" in *i*) if [ -r ~/.bashrc ]; then . ~/.bashrc; fi;; esac
~/.bash_profile or ~/.profile must end on :
. ~/.bashrc
for i in *tmp; do command $i; done