Shell Script
Shell Script
Shell Script
Introduction
Bug Reports
Basics
Quotes
Escape Sequences
2.1
2.1.1
Variables
2.2
Functions
2.3
Exit Status
2.4
Pattern Matching
2.5
#!
2.6
2.7
2.8
Arrays
Test
4
Operators
Subshells
Process Creation
Commands
Builtin Commands
4.1
5
5.1
6
6.1
read
6.1.1
printf
6.1.2
eval
6.1.3
getopt
6.1.4
Keyword Commands
6.2
Compound Commands
Special Expressions
Shell Metacharacters
Precedence
Expansions and Substitutions
Brace Expansion
9.1
10
10.1
Tilde Expansion
10.2
Parameter Expansion
10.3
Arithmetic Expansion
10.4
Command Substitution
10.5
Process Substitution
10.6
Word Splitting
10.7
Filename Expansion
10.8
Redirections
11
File Descriptors
11.1
<<< , <<
11.2
Pipe
11.3
Named Pipe
11.4
Buffering
11.5
Job Control
12
12.1
12.2
TTY
12.3
Mutual Exclusion
12.4
13
kill
13.1
trap
13.2
Signals Table
13.3
Shell Options
14
Shell Variables
15
Positional Parameters
15.1
Special Parameters
15.2
Command Aliases
16
Command History
17
Command Completion
18
Readline
19
Debugging
20
Dash
21
22
Tips
23
3
Recommand Sites
24
Introduction
Introduction
Bug Reports
.
NUL , / .
.
[ , [10 , [[AA , {echo , {AA=10}
shell .
.
command arg1 arg2 arg3 ...
shell script . if
[ shell builtin test
. ] .
Basics
# [ 10
$ [10 -eq 10 ]; echo $?
[10: command not found
# ] 10
$ [ 10 -eq 10]; echo $?
bash: [: missing ']'
# [ .
# a=b .
# "a=b" .
$ [ a=b ]; echo $?
0
# .
$ [ a = b ]; echo $?
1
--------------------------------------------------------# '{' echo '{echo' .
$ {echo 1; echo 2 ;}
bash: syntax error near unexpected token '}'
# .
$ { echo 1; echo 2 ;}
1
2
shell
. .
# AA = , 10 .
$ AA = 10
AA: command not found
# shell .
$ AA=10
$ echo $AA
10
shell script
.
Basics
if , 0 shell
. 0
. ( $? )
.
$? shell .
### 0 .
$ date -%Y #
date: invalid option -- '%'
Try 'date --help' for more information.
$ echo $? # 0 if .
1
$ date +%Y
2015
$ echo $? # 0 . if .
0
------------------------------------------------------------# . '$1'
$ f1() { return $1 ;}
# 'f1 0' 0
$ if f1 0; then echo true; else echo false; fi
true
# 'f1 1' 1
$ if f1 1; then echo true; else echo false; fi
false
return
shell return
. shell script exit
return .
Basics
c/c++, java ;
shell script .
. ;
. grouping { }
; .
# ';' .
$ for i in {1..3} do echo $i done
>
$ for i in {1..3}; do echo $i; done
1
2
3
# 'echo 2 }' '}' . ;
$ { echo 1; echo 2 }
>
$ { echo 1; echo 2 ;}
1
2
( ) shell subshell , ;
. .
# '(' ')' ; .
$ (echo hello; echo world)
hello
world
Escape
Basics
10
Shell . script
shell , , glob
escape quote
.
# shell glob '*'
$ expr 3 * 4
expr: syntax error
# quote escape
$ expr 3 '*' 4
$ expr 3 \* 4
12
# '<' , '>' shell redirection
# escape
$ [ a \< b ]
$ test a \> b
$ expr 3 \> 4
# '( )' ';' shell
$ find . -type f ( -name "*.log" -or -name "*.bak" ) -exec rm -f {} ;
bash: syntax error near unexpected token '('
# escape .
$ find . -type f \( -name "*.log" -or -name "*.bak" \) -exec rm -f {} \;
shell quote
IFS (Internal Field Separator : ) .
2
. Expansions and Substitutions -> Word Splitting
.
Basics
11
$ f1() {
echo arg1 : "$1"
echo arg2 : "$2"
}
$ AA="hello world"
$ f1 "$AA"
arg1 : hello world
arg2 :
# $AA quote f1 2 .
$ f1 $AA
arg1 : hello
arg2 : world
-------------------$ AA="hello world"
$ ARR=( "$AA" )
$ echo ${#ARR[@]}
1
# $AA quote ARR 2 .
$ ARR=( $AA )
$ echo ${#ARR[@]}
2
Basics
12
Misc.
. .
- -E --
--extended-regexp .
Short form
Long form
-o
--option
-o value
--option=value
-oltr
. grep
-n . -n
grep .
$ grep -r '-n' # '-n' .
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
-- " " .
# '--' end of options
$ grep -r -- -n # '--' '-n'
...
$ compgen -A file -- $cur
script -
-- .
command -o val -- "$arg1" "$arg2"
cd .
cd .
Basics
13
cd ~/tempdir
rm -rf *
cd .
cd ~/tempdir && rm -rf *
#
cd ~/tempdir || exit 1
...
cd ~/tempdir || { echo "cd ~/tempdir failed"; exit 1; }
...
Shell
Shell $ 3 .
3 .
: $AA, ${AA}, ${AA:-0}, ${AA//Linux/Unix} ...
: $(( 1 + 2 )) ...
: $( expr 1 + 2 ) ...
Basics
14
Quotes
Shell quotes . 123, "123",
'123' abc, "abc", 'abc' shell . shell
quotes .
no quotes , globbing
shell , , alias shell ,
echo printf quotes
. ( echo printf escape
. )
Quotes
15
, ,
(backtick)
history ( )
Quotes
16
$ AA=hello
$ echo $AA world `date +%Y` # $AA date .
hello world 2015
# escape
$ echo \$AA world \`date +%Y\`
$AA world `date +%Y`
escape
shell escape \ quote . quote
.
# ( ) ; shell quote . find .
# \( \) \; .
$ find . -type f '(' -name "*.log" -or -name "*.bak" ')' -exec rm -f {} ';'
# backgroun job & quote .
# \& .
$ echo hello '&'
hello &
# \ quote . \n .
# \\n .
$ echo hello world | tr ' ' '\'n
hello
world
# grep alias escape .
# \grep .
$ 'grep' 2015-07 data.txt
...
# shell time escape /usr/bin/time .
# \time .
$ 'time'
Usage: time [-apvV] [-f format] [-o file] [--append] [--verbose]
[--portability] [--format=format] [--output=file] [--version]
[--quiet] [--help] command [arg...]
No Quotes
no quotes shell , , alias, glob , quotes,
space, tab, newline escape disable .
Quotes
17
.
. no quotes escape . escape
.
----------- test.sh ----------#!/bin/bash
echo arg1 : "$1"
echo arg2 : "$2"
------------------------------$ ./test.sh hello world # 2
arg1 : hello
arg2 : world
$ ./test.sh hello\ world # escape .
arg1 : hello world
arg2 :
$ echo hello world # .
hello world
$ echo hello\ \ \ \ \ \ \world
hello world
no quotes escape .
# escape t n echo .
$ echo -e foo\tbar\n123
footbarn123
# \t \n echo escape .
$ echo -e foo\\tbar\\n123
foo bar
123
! history escape
$ date
Sat Jul 18 00:06:41 KST 2015
$ echo hello !!
echo hello date # history
hello date
$ echo hello \!! # escape history disable
hello !!
Quotes
18
\ escape
Quotes
19
$ echo "I
> like
> winter and snow"
I # .
like
winter and snow
##### #####
$ AA="this is
two lines"
$ echo $AA # .
this is two lines
$ echo "$AA" # .
this is
two lines
$ AA=hello
$ echo "$AA world `date +%Y`"
hello world 2015
# escape
$ echo "\$AA world \`date +%Y\`"
$AA world `date +%Y`
history \ .
escape .
# history '\' .
$ echo "hello\!516world"
hello\!516world
$ echo "hello"\!"516world"
hello!516world
$ echo "hello"'!'"516world"
hello!516world
Quotes
20
Array
double quotes array ${arr[@]}
quote "${arr[0]}" "${arr[1]}" "${arr[2]}" ... ${arr[*]}
quote "${arr[0]}X${arr[1]}X${arr[2]}X..." . X
IFS .
"$@" , "$*" positional parameters .
Single quotes
command string trap handler double quotes
.
1. command string
$ AA=100;
$ bash -c "AA=200; echo $AA" # double quotes
100
$ bash -c 'AA=200; echo $AA' # single quotes
200
2. trap handler
3. prompt
Quotes
21
$' '
' ' escape .
escape $ ' ' .
$ echo $'I like\n\'winter\'\tand\t\'snow\'' # \n, \t, \' escape .
I like
'winter' and 'snow'
-----------------------------------------$ IFS=$'\n'
$ IFS=$' \t\n'
Quotes
quotes .
.
' ' shell
' ' double quotes . quote
quote .
$ ./args.sh 11 "hello "$'$world \u2665' 33
$0 : ./args.sh
$1 : 11
$2 : hello $world
$3 : 33
Quotes
22
Escape Sequences
escape .
.
echo -e " " or ' '
$' '
Character represented
\\
backslash
\a
alert (bell)
\b
backspace
\e
\f
form feed
\n
newline
\r
carriage return
\t
horizontal tab
\v
vertical tab
\'
single quotes
$' '
\"
double quotes
\?
question mark
$' '
\<NNN>
8 N 8 . ( 1 ~ 3 )
$' '
\0<NNN>
8 N 8 . ( 1 ~ 3 )
echo
\x<HH>
8 H 16 . ( 1 ~ 2 )
\u<HHHH>
. H 16 . ( 1 ~ 4
)
\U<HHHHHHHH>
. H 16 . ( 1 ~ 8
)
\c
echo
\cx
$' '
Escape Sequences
printf
printf
printf
23
* .
Escape Sequences
24
Variables
(, ), , _
. shell .
subshell source child
process export . array export .
Variable States
Shell 3 .
1 . unset
( null )
. declare AA or local AA
. unset .
2 . null
null .
AA= AA="" AA=''
3 . null
.
AA=" " AA="hello" AA=123
3 ( 1, 2 )
.
# $var 1, 2
if [ -z "$var" ]; then ...
# $var 3
if [ -n "$var" ]; then ...
Variables
25
Variables
26
Shell Functions
group
context . group { ;} , ( )
{ ;} shell ( ) subshell .
{ ;} ( ) .
# echo hello world | read var; subshell
# echo "$var" .
$ echo hello world | read var; echo "$var"
# { } group read, echo context
# .
$ echo hello world | { read var; echo "$var" ;}
# hello world outfile .
$ echo hello; echo world > outfile
# group hello world outfile .
{ echo hello; echo world ;} > outfile
# group ( )
{
read var1
read var2
echo "$var1 $var2"
} < infile
f1() {
read var1
read var2
echo "$var1 $var2"
}
$ f1 < infile
(, ), , _
. return
. subshell source
child process export -f .
Functions
27
shell .
$1 $2 $3 ... . function bash
sh .
# shell .
X. ( p1 p2 p3 ) { ... ;}
1. () { ... ;}
2. function () { ... ;}
declare -f
shell
declare -F
unset -f
shell
compgen -A variable
# array
compgen -A arrayvar
unset -v
Functions
28
foo1 # foo1 .
foo1() {
echo "foo1"
foo2 # foo1 foo2
}
foo2() {
echo "foo2"
}
foo1 # foo1 .
global scope
global scope . ( source ).
#!/bin/bash
BB=200
foo() {
AA=100
}
foo
echo $AA # global scope
echo $BB
############### output ##############
100
200
local, declare .
declare local .
local declare global scope .
( sh local )
Functions
29
#!/bin/bash
foo() {
local AA=100
BB=200
}
foo
echo $AA
echo $BB
############### output ##############
200
local recursion
#
list_descendants ()
{
local children=$(ps -o pid= --ppid $1)
for pid in $children
do
list_descendants $pid
done
echo $children
}
$ ps jf $(list_descendants $$)
local child .
Shell local child .
parent . ( sh )
Functions
30
#!/bin/bash
AA=100
f1() {
local AA=200
f2
echo f1 AA after f2 call : $AA
}
f2() {
echo f2 AA : $AA # f1 local .
AA=300
}
f1
echo global AA : $AA
################ output ################
f2 AA : 200
f1 AA after f2 call : 300
global AA : 100
local . global scope
. ( sh )
Functions
31
#!/bin/bash
AA=100
f1() {
local AA=200
f1_1() {
echo f1_1 AA : $AA
AA=300
}
f1_1
echo f1 AA : $AA
}
f1
echo global AA : $AA
########### output ###########
f1_1 AA : 200
f1 AA : 300
global AA : 100
shell script return . shell
return exit
.
Functions
32
return .
.
. .
$ AA=$(expr 1 + 2)
$ echo $AA
3
$ AA=`date +%Y`
$ echo $AA
2015
Functions
33
f1() { expr $1 + $2 ;}
f2() { date "+%Y" ;}
f3() { echo "hello $1" ;}
------------------------$ AA=$(f1 1 2)
$ echo $AA
3
$ AA=`f2`
$ echo $AA
2015
$ AA=$(f3 world)
$ echo $AA
hello world
( ) ( )
. $1 $2 $3 ... positional parameters
scope local . $0 .
---------- test.sh -----------#!/bin/bash
echo
echo number of arguments: $#
echo '$0' : "$0"
echo '$1' : "$1"
echo '$2' : "$2"
echo '$3' : "$3"
echo '$4' : "$4"
echo '$5' : "$5"
------------------------------$ AA=(22 33 44)
$ test.sh 11 "${AA[@]}" "55 END"
number of arguments: 5
$0 : ./test.sh
$1 : 11
$2 : 22
$3 : 33
$4 : 44
$5 : 55 END
Functions
34
$@ , $* . quote
indirection array
Functions
35
#!/bin/bash
foo() {
echo "$1"
local ARR=( "${!2}" ) # '!2' 'AA[@]' .
for v in "${ARR[@]}"; do
echo "$v"
done
echo "$3"
}
AA=(22 "33 44" 55)
foo 11 'AA[@]' 66
################ output ###############
11
22
33 44
55
66
Functions
36
Functions
37
Exit Status
Shell script . . if,
while, until, ||, && , .
( ) .
# 0 .
$ if 0; then echo true; else echo false; fi
0: command not found
$ 0 && echo true
0: command not found
1 byte 0 ~ 255 . 0
. 1, 2, 126 ~ 165 shell
.
shell (subshell ) script exit
function source return .
0
( Success )
1
let "var = 1 / 0" : division by 0
2
Syntax error, builtin
test.sh: line 6: syntax error near unexpected token 'fi'
exit: 3.14: numeric argument required
126
Exit Status
38
excutable
bash: ./mylogfile.txt: Permission denied
127
()
typo $PATH
asdfg: command not found
128 + N
Signal N .
kill -9 PID $? 128 + 9 = 137
?
= , += . ;
. 0
.
Exit Status
39
# .
$ AA=11 BB=22 CC=33
$ echo $AA $BB $CC
11 22 33
--------------------------------------$ [ 1 -eq 2 ]
$ echo $?
1
# 0
$ [ 1 -eq 2 ]
$ AA=11
$ echo $?
0
------------------------------------------------# .
$ readlink -e asdfg; echo $?
1
$ AA=$( readlink -e asdfg ); echo $?
1
$ readlink -e test.sh; echo $?
/home/mug896/tmp/test.sh
0
$ AA=$(readlink -e test.sh); echo $?
0
$ echo $AA
/home/mug896/tmp/test.sh
# if .
if AA=$( readlink -e test.sh ); then ...
# local, declare .
$ AA=$( readlink -e asdfg ); echo $?
1
$ declare AA=$( readlink -e asdfg ); echo $?
0
Exit Status
40
Pattern Matching
Regex [[ ]] glob ( * , ? , [ ] )
shell script .
case
( substring removal, search and replace )
[[ ]]
filename matching ( globbing )
Glob
empty .
[ ... ]
bracket .
Bracket
[XYZ]
X, Y or Z .
[X-Z]
- range .
[[:class:]]
[^ ... ] or
[! ... ]
Pattern Matching
41
$ AA="inventory.tar.gz"
$ [[ $AA = *.tar.gz ]]; echo $?
0
$ [[ $AA = inventory.tar.?? ]]; echo $?
0
$ ls
address.class address.java read.c read.h write.c write.h
$ ls *.[ch]
read.c read.h write.c write.h
escape .
#!/bin/bash
AA='hello dog cat world'
[[ $AA = *dog\ cat* ]]; echo $?
Extended Pattern
shopt -s extglob shell . |
?(<PATTERN-LIST>)
zero or one .
*(<PATTERN-LIST>)
zero or more .
+(<PATTERN-LIST>)
one or more .
@(<PATTERN-LIST>)
one .
!(<PATTERN-LIST>)
! Not .
Pattern Matching
42
# *.jpg
$ ls !(*.jpg)
# *.jpg , *.gif , *.png
$ ls !(*.jpg|*.gif|*.png)
# AA leading space trailing space
$ AA=${AA##+([[:space:]])}; AA=${AA%%+([[:space:]])}
--------------------------------------------------$ AA=apple
$ [[ $AA = @(ba*(na)|a+(p)le) ]]; echo $?
0
$ AA=banana
$ [[ $AA = @(ba*(na)|a+(p)le) ]]; echo $?
0
$ AA=applebanana
$ [[ $AA = @(ba*(na)|a+(p)le) ]]; echo $?
1
$ [[ $AA = +(ba*(na)|a+(p)le) ]]; echo $?
0
Pattern Matching
43
#!
She (#) bang (!) shabang, hashbang
.
. shebang
.
#!/bin/bash # bash shebang line
...
#!/usr/bin/perl -T # perl shebang line
...
#!/bin/sed -f # sed shebang line
...
#!/usr/bin/awk -f # awk shebang line
...
#!
. OS #!
. foo
#!/bin/sed -f foo arg1 arg2 arg3
/bin/sed -f foo arg1 arg2 arg3 .
#!/bin/bash -x shebang bash ps .
shebang
shebang /bin/bash -m -f
.
$ /bin/bash -m -f script.sh
Portability
#!
44
#!/usr/bin/env shebang .
OS python /usr/bin/python
/usr/local/bin/python . OS
shebang . #!/usr/bin/env python
$PATH python .
python .
set uid .
root set uid shell script
. shell script
.
shebang line
shebang line . source
, ~/.bashrc , ~/.profile ,
...
#!
45
Script exec .
exec
script .
46
47
Login Shell
Login shell /etc/profile, ~/.bash_profile, ~/.bash_login, ~/.profile
. ( bash -l -c non-interactive login shell . )
Login shell logout ( exit) ~/.bash_logout .
Login shell shopt -s huponexit logout background
job HUP .
echo $0 -bash login shell .
Non-Login Shell
Interactive non-login shell .bashrc . interactive
non-interactive shell script .bashrc .
script BASH_ENV .
.rc : 1965 MIT Compatible Time-Sharing System (CTSS)
'run commands'
'runcom' . .rc .
Non-login shell su - userid bash -l login shell
.
48
.bashrc.d
shell , alias, . ~/.bashrc.d
. .d .bashrc
.
# ~/.bashrc
# alias
if [ -r ~/.bashrc.d/aliases ]; then
source ~/.bashrc.d/aliases
fi
#
for file in "$HOME"/.bashrc.d/functions/*.bash ; do
[ -r "$file" ] && source "$file"
done
#
for file in "$HOME"/.bashrc.d/completions/*.bash ; do
[ -r "$file" ] && source "$file"
done
unset -v file
49
Arrays
Array bash POSIX .
sh . array index indexed array
associative array . indexed array
associative array declare -A .
array empty AA=() unset -v AA .
array export .
Array
indexed array
declare -a array_name
local -a array_name ( )
associative array ( )
declare -A array_name
local -A array_name ( )
Array
AA=(11 22 33) array $AA 11 . AA[2]
$AA[2] $AA 11 11[2]
globbing . array { }
.
$ AA=(11 22 33)
# '112' globbing '112' .
$ echo $AA[2]
11[2]
$ echo ${AA[2]}
33
Array
$ AA=(apple banana orange)
$ declare -p AA
declare -a AA='([0]="apple" [1]="banana" [2]="orange")'
Arrays
50
@ , *
Double quotes ${array[@]} ${array[*]} .
IFS . " " quote @ *
. "array[@]" array " " quote
"array[*]" array " " IFS
.
Quote
${AA[@]}
${AA[*]}
quote
"${AA[@]}"
"${AA[*]}"
"${AA[0]}X${AA[1]}X${AA[2]}..."
'X' IFS
Arrays
51
# 5 .
$ AA=( "Arch Linux" "Ubuntu Linux" "Fedora Linux" )
$ echo ${#AA[@]}
3
# quote IFS
# for 6
$ echo ${AA[@]} # .
Arch Linux Ubuntu Linux Fedora Linux
$ for v in ${AA[@]}; do echo "$v"; done # 6
Arch
Linux
Ubuntu
Linux
Fedora
Linux
$ echo ${AA[*]} # .
Arch Linux Ubuntu Linux Fedora Linux
$ for v in ${AA[*]}; do echo "$v"; done
Arch
Linux
Ubuntu
Linux
Fedora
Linux
################# quote #################
$ echo "${AA[@]}"
Arch Linux Ubuntu Linux Fedora Linux # .
$ echo "${AA[*]}"
Arch Linux Ubuntu Linux Fedora Linux
$ for v in "${AA[@]}"; do echo "$v"; done # "array[@]" .
Arch Linux
Ubuntu Linux
Fedora Linux
$ for v in "${AA[*]}"; do echo "$v"; done # "array[*]" 1 .
Arch Linux Ubuntu Linux Fedora Linux
${arr[@]} ?
Arrays
52
$ AA=(1 2 3 4 5)
$ args.sh "aa ${AA[@]} bb" # .
$1 : aa 1
$2 : 2
$3 : 3
$4 : 4
$5 : 5 bb
--------$ args.sh "aa ${AA[*]} bb"
$1 : aa 1 2 3 4 5 bb
${#array[@]}
${#array[*]}
array
${#array[N]}
${#array[string]}
${array[@]}
${array[*]}
array value
${!array[@]}
${!array[*]}
array index
${!name@}
${!name*}
name
) echo "${!BASH@}"
Array
index [ ] (( ))
.
Arrays
53
Array iteration
########## indexed array #########
ARR=(11 22 33)
for idx in ${!ARR[@]}; do
echo ARR index : $idx, value : "${ARR[idx]}" # ${ARR[$idx]}
done
######## associative array ########
declare -A ARR
ARR=( [ab]=11 [cd]="hello array" [ef]=22 )
for idx in "${!ARR[@]}"; do
echo ARR index : "$idx", value : "${ARR[$idx]}"
done
Array
array AA BB BB=${AA[@]} array AA BB
. array ( ) .
Arrays
54
$ AA=( 11 22 33 )
$ BB=${AA[@]}
$ echo "${BB[1]}" # array .
$ echo "$BB" # array AA BB .
11 22 33
$ BB=( "${AA[@]}" ) # array '( )'
$ echo "${BB[1]}"
22
Array
array [ ] glob globbing quote
.
array=()
unset -v array
unset -v "array[@]"
array
unset -v "array[N]"
indexed array N
unset -v "array[string]"
Arrays
55
$ AA=(11 22 33 44 55)
$ unset -v "AA[2]"
$ echo ${#AA[@]} #
4
$ for v in "${AA[@]}"; do echo "$v"; done
11 # for .
22
44
55
$ echo ${AA[1]} : ${AA[2]} : ${AA[3]} # index 2 !
22 : : 44
$ AA=( "${AA[@]}" ) # index
$ echo ${AA[1]} : ${AA[2]} : ${AA[3]}
22 : 44 : 55
Array
Arrays
56
array ${array[@]:offset:length} .
$ AA=( Arch Ubuntu Fedora Suse Mint );
$ echo "${AA[@]:2}"
Fedora Suse Mint
$ echo "${AA[@]:0:2}"
Arch Ubuntu
$ echo "${AA[@]:1:3}"
Ubuntu Fedora Suse
Array
$ AA=( "Arch Linux" Ubuntu Fedora);
$ AA=( "${AA[@]}" AIX HP-UX);
$ echo "${AA[@]}"
Arch Linux Ubuntu Fedora AIX HP-UX
#######################################
$ BB=( 11 22 33 )
$ echo ${#BB[@]}
3
$ BB+=( 44 )
$ echo ${#BB[@]}
4
#######################################
$ declare -A AA=( [aa]=11 [bb]=22 [cc]=33 )
$ echo ${#AA[@]}
3
$ AA+=( [dd]=44 )
$ echo ${#AA[@]}
4
array
. # ,
% anchor .
Arrays
57
$ AA=( "Arch Linux" "Ubuntu Linux" "Suse Linux" "Fedora Linux" )
# "${AA[*]}" "elem1Xelem2Xelem3X..." .
# IFS '\n' echo
# '\n' array .
$ set -f; IFS=$'\n'
$ AA=( $(echo "${AA[*]/Su*/}") )
$ set +f; IFS=$' \t\n' # array IFS
$ echo ${#AA[@]} # 3
3
$ echo "${AA[1]} ${AA[2]}" # index .
Ubuntu Linux Fedora Linux
.
Arrays
58
array
$ cat datafile
100 Emma Thomas
200 Alex Jason
300 Madison Randy
$ mapfile -t arr < datafile
$ echo "${arr[0]}"
100 Emma Thomas
$ echo "${arr[1]}"
200 Alex Jason
Arrays
59
Array index .
[ ] .
$ AA=(1 2 3 4 5)
$ idx=2
$ echo "${AA[idx == 3 ? 1 : 2]}"
3
Arrays
60
Test
shell . .
shell script .
? ?
expr, bc . shell script
.
.
# .
# c main
int main(int argc, char **argv)
# java main
public static void main(String[] args)
32 ? "32" ?
. shell
32 , "32" .
.
# "16" 16
$ printf "decimal: %d, float: %g, hex: %x, string: %s\n" "-16" "16.1" "16" 16
decimal: -16, float: 16.1, hex: 10, string: 16
# '+' expr
$ expr "-16" + 10
-6
# '*' glob escape
$ echo "10" + 2 \* 5 | bc
20
# '-gt' "150" .
$ [ "150" -gt 25 ]; echo $?
0
# quote .
$ [ "150" -gt "25" ]; echo $?
0
Test
61
shell script
.
. test help
.
String operators: #
-z STRING True if string is empty.
-n STRING
STRING True if string is not empty.
STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.
#
arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.
[ ] , test
.
test , [ . test [ . [
command arg1 arg2 ... . help
[ ] .
# test '[' .
$ test -d /home/user/foo; echo $?
1
$ [ -d /home/user/foo ]; echo $?
1
null true
[ null false
true .
Test
62
########## ##########
$ [ ]; echo $?
1
$ [ "" ]; echo $?
1
$ [ "$asdfgh" ]; echo $? #
1
$ AA=""
$ [ "$AA" ]; echo $? # null
1
####### null true #######
$ [ 0 ]; echo $?
0
$ [ 1 ]; echo $?
0
$ [ a ]; echo $?
0
$ [ -n ]; echo $?
0
false 0 ?
true false 0 . true
false shell builtin .
true 0 false 1 . [
"false" .shell null true .
Bourne shell true, false true colon : alias
.
$ [ true ]; echo $?
0
$ [ false ]; echo $?
0
# if true, false .
$ if false; then echo true; else echo false; fi
false
$ if true; then echo true; else echo false; fi
true
quote .
Test
63
[ quote .
AA null echo
. -n $AA quote [
-n hello world ] .
$ AA="hello world"
$ if [ -n $AA ]; then
echo "$AA"
fi
bash: [: too many arguments
[ quote .
.
< , > [ ] , [[ ]]
. help
(lexicographically) . "100" "2" .
"1" "2" .
$ [ 100 \> 2 ]; echo $?
1
$ [ 100 -gt 2 ]; echo $?
0
AND , OR
Test
64
. [
, shell
( shell metacharacters precedence ).
# shell
if [ test1 ] && [ test2 ]; then ...
if [ test1 ] || [ test2 ]; then ...
# { ;}
if [ test1 ] || { [ test2 ] && [ test3 ] ;} then ...
---------------------------------------------------if [ test1 -a test2 ]; then ...
if [ test1 -o test2 ]; then ...
# `( )` shell escape .
if [ test1 -a \( test2 -o test3 \) ]; then ...
Logical NOT
.
# '[' '!'
if [ ! test1 ]; then ...
# shell logical NOT
if ! [ test1 ]; then ...
Array *
Quote ${array[@]} ${array[*]} . IFS
. " " @ *
. @ " " * " "
. array * .
Test
65
$ AA=(11 22 33)
$ BB=(11 22 33)
$ [ "${AA[*]}" = "${BB[*]}" ]; echo $?
0
$ [ "${AA[@]}" = "${BB[@]}" ]; echo $?
bash: [: too many arguments
[[ ]]
[ ] . [ ] [ ]
[[ ]] shell keyword . keyword
shell [
. ( Special Expressions ).
# '<' , '>' quote .
$ [[ a < b ]]; echo $?
0
$ [[ a > b ]]; echo $?
1
# quote .
$ AA=""
$ [[ -n $AA ]]; echo $?
1
$ [[ -n "$AA" ]]; echo $?
1
Test
66
Test Operators
test , [ builtin [[ ]]
. ( -a , -o )
File Tests
test symbolic link -L , -h
. AA symbolick link BB.sh
[ -L AA ] , [ -f AA ] true .
Operators
67
-a <FILE>
true .
( Logical AND
. )
-e <FILE>
true .
-f <FILE>
regular true .
-d <FILE>
directory true .
-c <FILE>
-b <FILE>
-p <FILE>
-S <FILE>
socket true .
-L <FILE>
-h <FILE>
-g <FILE>
-u <FILE>
-k <FILE>
-r <FILE>
readable true .
-w <FILE>
writable true .
-x <FILE>
executable true .
-O <FILE>
-G <FILE>
-N <FILE>
-s <FILE>
-t <fd>
FD true .
<FILE1> -nt
<FILE2>
<FILE1> -ot
<FILE2>
<FILE1> -ef
<FILE2>
String Tests
Operators
68
-z <STRING>
null true .
( . )
-n <STRING>
null true .
<STRING1> = <STRING2>
true .
<STRING1> != <STRING2>
true .
1 true .
( escape . )
1 true .
( escape . )
Arithmetic Tests
<INTEGER1> -eq
<INTEGER2>
true .
<INTEGER1> -ne
<INTEGER2>
true .
<INTEGER1> -ge
<INTEGER2>
Misc Syntax
Operators
69
<TEST1> -a
<TEST2>
AND .
-a .
<TEST1> -o
<TEST2>
OR .
! <TEST>
Logical NOT .
( <TEST> )
( escape . )
-o
<OPTION_NAME>
set builtin
.
-o true, +o false .
-v
<VARIABLENAME>
.
(unset ) 1 , 0
.
-R
<VARIABLENAME>
Operators
70
Subshells
Shell .
process parent child process .
/bin/sleep bash shell process sleep child
process .
4 . shell
script bash child process sleep
. ( ) $( ) ` ` | &
shell subshell .
$ ( echo; sleep 10 ) # 1. ( ) , $( )
$ `echo; sleep 10` # 2. ` ` backtick
$ echo | { echo; sleep 10; } # 3. |
$ shellfunc & { comm1; comm2 ...;} & # 4. background group
Subshells
71
Subshells
72
Subshell
export shell ,
trap handler ( trap 'rm -f tmpfile' INT )
pid $$
parent pid $PPID
subshell shell . subshell
shell .
Subshells
73
Subshell
parent process export child process
. subshell export .
$ AA=100
$ ( echo AA value = "$AA" ) # AA export .
AA value = 100
Subshells
74
shell subshell , .
shell .
$ AA=100
$ ( AA=200; echo AA value = "$AA" ) # subshell 200 .
AA value = 200
$ echo "$AA" # shell .
100
Subshells
75
$ echo -n "$IFS" | od -a
0000000 sp ht nl
# subshell IFS ':' .
$ ( IFS=:; echo -n "$IFS" | od -a )
0000000 :
# subshell IFS .
$ echo -n "$IFS" | od -a
0000000 sp ht nl
##################################################
$ [ -o noglob ]; echo $?
1
# subshell .
$ ( set -o noglob; [ -o noglob ]; echo $? )
0
# subshell .
$ [ -o noglob ]; echo $?
1
##################################################
$ set -- 11 22 33
$ echo "$@"
11 22 33
# positional parameters subshell
$ ( set -- 44 55 66; echo "$@" )
44 55 66
# subshell
$ echo "$@"
11 22 33
##################################################
$ ulimit -c
0
# core file subshell ulimit
$ ( ulimit -c unlimited; ulimit -c ; ... )
unlimited
# subshell 'ulimit -c' 0
$ ulimit -c
0
Subshells
76
subshell cd .
$ pwd
/home/test/tmp
# subshell cd
$ ( cd ~/tmp2; pwd; ... )
/home/test/tmp2
# subshell
$ pwd
/home/test/tmp
subshell exit .
$ ( echo hello; exit 3; echo world )
hello
$ echo $?
3
$$ $BASHPID
$$ shell pid subshell .
$SHLVL $BASH_SUBSHELL
SHLVL child process , BASH_SUBSHELL subshell .
1. .
SHLVL 1 (shell process ), BASH_SUBSHELL 0 .
2.
( ) subshell
BASH_SUBSHELL .
3. shell script
child process SHLVL .
4. bash -c 'command ...' [ arg1 arg2 ... ]
child process SHLVL .
Subshells
77
Subshell
shell script subshell .
.1
#!/bin/bash
index=30
change_index() {
index=40
echo "changed to 40"
}
result=$(change_index)
echo $result
echo $index
########### output ###########
changed to 40
30
.2
$ echo hello | read var; echo $var
$
$ echo hello | { read var; echo $var; }
$ hello
.3
Subshells
78
#!/bin/bash
nKeys=0
cat datafile | while read -r line
do
#...do stuff
nKeys=$((nKeys + 1))
done
echo Finished writing $nKeys keys
########### output ###########
Finished writing 0 keys
Subshells
79
Process Creation
.
subshell parent shell export ,
?
child process export , ?
export ?
subshell, child process parent shell ?
parent shell subshell, child process
?
shell ( ) $( ) ` ` | & ?
Process PCB
Process Creation
80
1 ( ) .
.
Operating System . OS
PID,PPID , ( stopped, running ... ) ,
, cpu
2 PCB (Process Control Block) . PCB 100
.
Shell , , , alias ,
1 .
. A ,
. parent shell
subshell, child , subshell, child
parent shell .
( ) $( ) ` ` | & subshell
shell
.
OS
shared memory, massage passing IPC (Interprocess Communication)
.
Process
subshell child process .
fork, exec, exit, wait OS system call .
Process Creation
81
1. ls
2. fork
fork unix . pid,
ppid (4). fork ,
PCB . bash shell
. $$ $PPID
export .
subshell . subshell $BASHPID pid
.
3. exec
Process Creation
82
exec . bash
exec ls (5).
bash
.
exec ( export , ) child
process . shell export
bash shell child process
.
4. exit
child exit .
PCB parent wait
. child parent wait child
OS .
parent child child pid 1 init
reparent init wait
.
5. continue
fork-exec
shell fork exec
. fork-exec
shell fork subshell exec exec builtin
.
$ date
Mon Dec 28 13:49:17 KST 2015
$ ( exec date )
Mon Dec 28 13:49:25 KST 2015
subshell child
subshell parent pid child . exec
.
Process Creation
83
1.
/usr/bin/find .
builtin .
2. shell builtins
Shell builtin
shell .
$ compgen -b | column
. : [ alias bg bind break
builtin caller cd command compgen complete compopt
continue declare dirs disown echo enable eval
exec exit export false fc fg getopts
hash help history jobs kill let local
logout mapfile popd printf pushd pwd read
readarray readonly return set shift shopt source
suspend test times trap true type typeset
ulimit umask unalias unset wait
3. shell functions
. , builtin
. declare -F shell
.
4. shell keywords
command arg1 arg2 ...
.
$ compgen -k | column
if then else elif fi case
esac for select while until do
done in function time { }
! [[ ]] coproc
Commands
84
5. aliases
alias . shell alias
. Non-interactive shell script disable
.
.
builtin type .
$ type -a kill
kill is a shell builtin
kill is /bin/kill
$ type -a time
time is a shell keyword
time is /usr/bin/time
$ type -a [
[ is a shell builtin
[ is /usr/bin/[
Commands
85
function builtin
escape . builtin
enable builtin disable .
.1
shell builtin [ [[ .
$ AA="hello world"
$ if [ -n $AA ]; then
> echo "$AA"
> fi
bash: [: hello: binary operator expected
---------------------------------------$ if [[ -n $AA ]]; then
> echo "$AA"
> fi
hello world
[ [[ . [
builtin . command arg1
arg2.. . [ -n $AA ] [ -n hello world ]
Commands
86
.2
builtin .
$ a='['
$ $a -d /tmp ]
$ echo $?
0
$a [ -d /tmp ] .
$ a='[['
$ $a -d /tmp ]]
bash: [[: command not found
$a [[ -d /tmp ]] .
.
[[ .
.3
time shell /usr/bin/time .
.
$ time { find . -name '*.sh' | wc -l ;}
24
real 0m0.002s
user 0m0.000s
sys 0m0.004s
\ escape /usr/bin/time
.
$ \time { find . -name '*.sh' | wc -l ;}
bash: syntax error near unexpected token `}'
Commands
87
Help
Shell builtins, keywords
help command
$ help set
set: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
Set or unset values of shell options and positional parameters.
...
...
Commands
88
1. command --help
2. man command
3. info command
man page ( manual page ) unix .
.
User Commands
System Calls
C Library Functions
Games
man -f page
.
$ man -f printf
printf (3) - formatted output conversion
printf (1) - format and print data
man -k regex
.
$ man -k printf
asprintf (3) - print to allocated string
dprintf (3) - print to a file descriptor
fprintf (3) - formatted output conversion
fwprintf (3) - formatted wide-character output conversion
printf (1) - format and print data
...
...
Commands
89
man page .
1990 GNU man page info . info
hyperlink markup language man page
.
$ info grep
Commands
90
:
:
. 0 . true
( true alias . ).
true . ,
, .
.
while :; do echo $(( i++ )); sleep 1; done
if :; then :; else :; fi
# DIR null '/usr/local'
: ${DIR:=/usr/local}
break
break [n]
for, while, until .
. n .
cd
Builtin Commands
91
continue
continue [n]
for, while, until . continue
. n .
eval
eval [arg ...]
eval .
exec
exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
shell process command .
command exit . ( exit execfail
. )
shell redirection .
exit
exit [n]
shell exit . n $? . n
.
export
export [-fn] [name[=value] ...] or export -p
AA.sh BB.sh ( source ) AA.sh parent,
BB.sh child process . AA.sh BB.sh
export child process BB.sh
.
Builtin Commands
92
getopts
getopts optstring name [arg]
.
hash
hash [-lr] [-p pathname] [-dt] [name ...]
.
pwd
pwd [-LP]
. $PWD -P
.
readonly
readonly [-aAf] [name[=value] ...] or readonly -p
. 1 .
return
return [n]
function source . n $?
. return
.
shift
shift [n]
positional parameters .
Builtin Commands
93
test
test [expr]
Test .
trap
trap [-lp] [[arg] signal_spec ...]
trap .
umask
umask [-p] [-S] [mode]
User file-creation mode mask
8 . mask ( 000 ) 666,
777 . 022 666
644 755 .
.
unset
unset [-f] [-v] [-n] [name ...]
. readonly
unset . AA=, AA="", AA='' null ( set )
. unset . [ -v name ]
. name $ .
Bash Builtins
[
[ arg... ]
test . Test .
alias
alias [-p] [name[=value] ... ]
Builtin Commands
94
bg
bg [job_spec ...]
job control
bind
bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x
keyseq:shell-command] [keyseq:readline-function or readline-command]
readline inputrc , key binding
.
.
builtin
builtin [shell-builtin [arg ...]]
alias, function builtin .
caller
caller [expr]
call stack . ,
( ${BASH_LINENO[0]} ${BASH_SOURCE[1]} ) , ,
( ${BASH_LINENO[$i]} ${FUNCNAME[$i+1]} ${BASH_SOURCE[$i+1]} ) . stack
trace .
Builtin Commands
95
#!/bin/bash
die() {
local frame=0
while caller $frame; do
((frame++));
done
echo "$*"
exit 1
}
f1() { die "*** an error occured ***"; }
f2() { f1; }
f3() { f2; }
f3
################ output #################
12 f1 ./callertest.sh
13 f2 ./callertest.sh
14 f3 ./callertest.sh
16 main ./callertest.sh
*** an error occured ***
command
command [-pVv] command [arg ...]
alias, function (builtin ) .
-v .
compgen
compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [C command] [-X filterpat] [-P prefix] [-S suffix] [word]
.
COMPREPLY . complete
word word .
complete
Builtin Commands
96
complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F
function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
.
compopt
compopt [-o|+o option] [-DE] [name ...]
complete .
declare
declare [-aAfFgilnrtux] [-p] [name[=value] ...]
. (unset )
. , array .
non-zero .
Associative array declare -A .
local .
-g global .
declare -n named reference .
declare -t -f DEBUG, RETRUN trap
.
Options:
-f
.
action .
-F
.
( line number source file .)
-g
declare local .
global .
-p
NAME .
- + off .
Builtin Commands
97
-a
-A
-i
NAME integer .
let .
-n
-r
NAME readonly .
-t
NAME trace .
-l
NAME .
-u
NAME .
-x
NAME export .
dirs
dirs [-clpv] [+N] [-N]
pushd, popd directory stack stack
. 0 .
disown
disown [-h] [-ar] [jobspec ...]
job control
echo
echo [-neE] [arg ...]
escape newline
-n . quote (single, double quotes) -e
escape .
enable
enable [-a] [-dnps] [-f filename] [name ...]
builtin disable enable . builtin
builtin disable .
Builtin Commands
98
false
false
1 .
.
$ echo false
false
$ false
$ echo $?
1
fc
fc [-e ename] [-lnr] [first] [last]
command history
.
fc -s [pat=rep] [command]
! history .
fg
fg [job_spec]
job control
help
help [-dms] [pattern ...]
Shell builtin .
history
Builtin Commands
99
history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]
command history .
jobs
jobs [-lnprs] [jobspec ...] or jobs -x command [args]
job control
kill
kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
kill .
let
let arg [arg ...]
. .
quote . special expressions
local
local [option] name[=value] ...
local . . declare
. local child
function . parent function
.
logout
logout [n]
login shell logout . login shell .
mapfile
mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
Builtin Commands
100
-t
newline .
-s count
.
-n count
. 0 .
-O origin
array index .
-u fd
file descriptor .
array callback .
-C callback
callback .
-c quantum
callback .
Builtin Commands
101
$ cat datafile
100 Emma Thomas
200 Alex Jason
300 Madison Randy
400 Sanjay Gupta
500 Nisha Singh
# callback $1 index , $2 .
$ f1() { echo "$1 : $2" ;}
$ mapfile -t -C f1 -c 1 < datafile # -c 1
0 : 100 Emma Thomas
1 : 200 Alex Jason
2 : 300 Madison Randy
3 : 400 Sanjay Gupta
4 : 500 Nisha Singh
$ mapfile -t -C f1 -c 2 < datafile # -c 2
1 : 200 Alex Jason
3 : 400 Sanjay Gupta
$ mapfile -t -C f1 -c 3 < datafile # -c 3
2 : 300 Madison Randy
popd
popd [-n] [+N | -N]
pushd, dirs directory stack stack
.
printf
printf [-v var] format [arguments]
Builtin Commands
102
printf
pushd
pushd
popd, dirs directory stack
stack .
read
read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u
fd] [name ...]
read .
readarray
readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
mapfile .
set
set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
Shell option $1 $2 $3 ...
. enable $SHELLOPTS : $-
flags . enable - disable +
. [ -o ] .
shopt
shopt [-pqsu] [-o] [optname ...]
Bash option . enable $BASHOPTS :
. enable -s disable -u -q
.
Builtin Commands
103
$ shopt -s nullglob
$ shopt -q nullglob; echo $?
0
$ shopt -u nullglob
$ shopt -q nullglob; echo $?
1
source
source filename [arguments]
. (a period) .
suspend
suspend [-f]
job control
true
true
0 .
.
$ echo true
true
$ true
$ echo $?
0
type
type [-afptP] name [name ...]
-a alias, function, keyword, builtin,
typeset
Builtin Commands
104
ulimit
ulimit [-SHabcdefilmnpqrstuvxT] [limit]
shell . hard limit (-H) root soft limit (-S)
hard limit . shell child
process .
.
startup script ulimit
reboot .
pid cat /proc/{pid}/limits
.
# .
/etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
root soft nofile 65536
root hard nofile 65536
---------------------------------------/etc/pam.d/common-session-noninteractive
/etc/pam.d/common-session
session required pam_limits.so
unalias
unalias [-a] name [name ...]
alias .
wait
wait [-n] [id ...]
Builtin Commands
105
job control
Builtin Commands
106
read
read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u
fd] [name ...]
read stdin IFS [name
...] . awk record field
read IFS .
read
107
subshell .
$ echo 1 2 3 4 5 | read v1 v2 v3
$ echo $v1 $v2 $v3
-------------------------------# group .
$ echo 1 2 3 4 5 | { read v1 v2 v3; echo $v1 $v2 $v3 ;}
1 2 3 4 5
IFS .
$ IFS=, read -a arr <<< "1,2,3,4,5"
$ echo ${#arr[@]}
5
$ IFS=, read -a arr <<< "1,2,3,4," # array .
$ echo ${#arr[@]}
4
Options
-r : \ escape disable (raw read).
.
-d delim : newline .
read
108
-a array : array .
$ read -ra arr <<< "1 2 3 4 5"
$ echo ${#arr[@]}
5
$ echo ${arr[1]}
2
-p prompt : prompt .
-e : readline .
-i text : -e , .
-s : .
$ read -p "Enter the path to the file: " -ei "/usr/local/" reply
Enter the path to the file: /usr/local/bin
$ echo "$reply"
/usr/local/bin
-n nchars : nchars . .
-N nchars : nchars .
read
109
$ read -n 8 v1 <<END
12345
6789
END
# newline 5 .
$ echo "$v1"
12345
-------------------$ read -N 8 v1 <<END
12345
6789
END
# newline 7 .
$ echo "$v1"
12345
67
----------------------------------------asksure() {
echo -n "Are you sure (Y/N)? "
while read -n 1 answer; do
if [[ $answer = [YyNn] ]]; then
[[ $answer = [Yy] ]] && return 0
[[ $answer = [Nn] ]] && return 1
break
fi
done
}
----------------------------------------pause() {
read -s -n 1 -p "Press any key to continue..."
}
-t timeout : timeout .
timeout 0
. 0 128
.
-u fd : stdin file descriptor .
read
110
0 .
end-of-file
read times out ( 128 .)
-u FD (file descriptor)
end-of-file .
newline ( newline
). read end-of-file .
-d null newline
end-of-file .
$ echo -n hello > tmpfile
$ cat tmpfile | od -a # newline .
0000000 h e l l o
$ read -r v1 < tmpfile
$ echo $? # end-of-file .
1
$ echo "$v1"
hello
read
111
printf
printf [-v var] format [arguments]
printf single, double quotes escape . quotes
double quotes , .
$ AA=world
# double quotes
$ printf "hello\t$AA\n" # \t \n escape .
hello world
# single quotes
$ printf 'hello\t$AA\n' # \t \n escape .
hello $AA
Arguments
printf format tags .
.
N : 10 (decimal)
0N : 8 (octal)
0xN : 16 (hexadecimal)
0XN : 16 (hexadecimal)
'X : X a character
"X : X a character
printf
112
# %d 10
$ printf "%d\n" 10 # decimal
10
$ printf "%d\n" 010 # octal
8
$ printf "%d\n" 0x10 # hexadecimal
16
$ printf "%d\n" "'A" # a character
65
format tags .
$ printf "< %d >" 11
< 11 >
$ printf "< %d >" 11 22 33 # %d 3 3
< 11 >< 22 >< 33 >
$ printf "< %d >\n" 11
< 11 >
$ printf "< %d >\n" 11 22 33
< 11 >
< 22 >
< 33 >
Format Tags
format format tag
.
%[flags][width][.precision]specifier
Specifier
%d, %i : signed decimal number .
%u : unsigned decimal number .
%o : unsigned octal number .
%x : unsigned hexadecimal number () .
%X : %x .
printf
113
printf
114
%s : escape .
%b : escape .
printf
115
# 'bash -c CMD' .
$ echo 'echo -e "first\nsecond"' | xargs -I CMD bash -c CMD
firstnsecond # \n .
$ printf "%q\n" 'echo -e "first\nsecond"'
# echo\ -e\ \"first\\nsecond\"
$ printf "%q\n" 'echo -e "first\nsecond"' | xargs -I CMD bash -c CMD
first
second
----------------------------------------------------------------$ cat commands.txt
echo -e "first\nsecond"
echo -e "third\nfourth"
echo -e "fifth\nsixth"
$ cat commands.txt | \
while read -r CMD; do printf "%q\n" "$CMD"; done | \
xargs --max-procs=3 -I CMD bash -c CMD
---------------------------------------------------------------# touch
sshc() {
remote=$1; shift
ssh "$remote" "$(printf "%q " "$@")"
}
$ printf "%q " touch "a test file" "another file"
touch a\ test\ file another\ file
$ sshc user@server touch "a test file" "another file"
%% : % .
%c : .
%(FORMAT)T : FORMAT date-time .
%n : . ( bash only )
printf
116
Width
N : field width .
* : field width .
Flags
- : field width left . ( default right . )
+ : + , - sign .
printf
117
# : alternative format .
%#o octal number 0 .
$ printf "%#o\n" 10
012
Precision
. field width precision .
printf
118
%f %g precision .
%f %g .
%.s or %.0s .
$ printf "%5d%5d%.s%.0s%5d\n" 11 22 33 44 55
11 22 55
)
0 ~ 127 decimal, octal, hexadecimal
$ for ((x=0; x <= 127; x++)); do
> printf '%3d | %04o | 0x%02x\n' $x $x $x
> done
0 | 0000 | 0x00
1 | 0001 | 0x01
2 | 0002 | 0x02
...
...
125 | 0175 | 0x7d
126 | 0176 | 0x7e
127 | 0177 | 0x7f
1 ~ 2 hexadecimal number 2
printf
119
$ mac_addr="0:13:ce:7:7a:ad"
$ printf "%02x:%02x:%02x:%02x:%02x:%02x\n" 0x${mac_addr//:/ 0x}
00:13:ce:07:7a:ad
tput cols columns . echo $COLUMNS
printf
120
eval
eval [ arg . . . ]
eval shell .
eval .
# echo foo bar .
$ $( echo "echo foo bar" )
foo bar
shell , shell
. ,
shell .
$ $( echo "if test 1 -eq 1; then echo equal; fi" )
if: command not found
$ $( awk 'BEGIN { print "AA=100" }' )
AA=100: command not found
eval .
$ eval "$( echo "if test 1 -eq 1; then echo equal; fi" )"
equal
$ eval "$( awk 'BEGIN { print "AA=100" }' )"
$ echo $AA
100
eval
eval .
. . , . .
. .
eval
121
$ AA=100 BB=200
# , $BB 200
# quotes .
$ echo '$AA' $BB
$AA 200
# 1. eval , quotes .
# echo $AA 200
# 2. , $AA 100 .
$ eval echo '$AA' $BB
100 200
# 1. single quotes escape read .
# echo '$AA' 200
# 2. quotes .
$ eval echo \''$AA'\' $BB
$AA 200
brace range ( )
eval brace .
$ a=1 b=5
# 1. eval read .
# echo {1..5}
# 2. brace .
$ eval echo {$a..$b}
1 2 3 4 5
eval .
echo $A, $B, $C
.
$ A=1 B=2 C=3
$ A=4 B=5 C=6 echo $A $B $C
1 2 3
eval .
eval
122
$ AA='find . -name'
$ BB='"*.sh"'
$ eval "$AA $BB"
args.sh
sub.sh
test.sh
...
...
eval .
eval
123
$ AA=BB
$ echo $AA
BB
$ eval $AA=100
$ echo $BB
100
$ main() {
> local fbody='() { echo "function name is : $FUNCNAME"; }'
> local fname
> for fname in f{1..10}; do
> eval "${fname}${fbody}" #
> $fname #
> done
> }
$ main
function name is : f1
function name is : f2
function name is : f3
...
...
eval
124
getopt
getopt optstring parameters
getopt [options] [--] optstring parameters
getopt [options] -o|--options optstring [options] [--] parameters
getopt, getopts . getopts builtin
short getopt
.
short long (
optarg ) . short .
short
$ script.sh -a -b -c arg1 arg2 ...
$ script.sh -abc arg1 arg2 ... # short
$ script.sh -a optarg -bc arg1 arg2 ... # ( optarg ) .
long
$ script.sh --optionA --optionB arg1 arg2 ...
$ script.sh --optionA optarg --optionB arg1 arg2 ... # ( optarg ) .
.
# hello, world .
$ script.sh -a optarg --optionA optarg hello -bc world --optionB
. getopt
case .
, case .
getopt
125
#
$ script.sh -a optarg --optionA optarg hello -bc world --optionB
# getopt .
-a 'optarg' -b -c --optionA 'optarg' --optionB -- 'hello' 'world'
--
, -bc short
.
getopt
getopt -n "$(basename "$0")" -o a:,b,c -l optionA:,optionB -- "$@"
# -n .
# -o short .
# ',' ( optarg )
# ':' .
# -l long .
# ':' .
# ( -- ) ( $@ ) .
--------------------------------------------------------------------------------#!/bin/bash
# getopt " ", " " .
options=$( getopt -n "$(basename "$0")" -o a:,b,c -l optionA:,optionB -- "$@" )
[ $? -ne 0 ] && exit 1
set -- $options
# "$@" .
# -a 'optarg' -b -c --optionA 'optarg' --optionB -- 'hello' 'world'
while true; do
case $1 in
-a )
optarg=$2
echo "option : $1, optarg : $optarg"
shift
;;
-b | --optionB )
echo "option : $1"
;;
getopt
126
-c )
echo "option : $1"
;;
--optionA )
optarg=$2
echo "option : $1, optarg : $optarg"
shift
;;
-- )
shift
break
;;
esac
shift
done
# "$@" .
# 'hello' 'world'
echo "\$1 : $1"
echo "\$2 : $2"
getopt
127
Keyword Commands
time
time [-p] pipeline
. { } , ( )
group . TIMEFORMAT
.
real
wall clock .
I/O wait sleep .
$ time { sleep 1; sleep 2 ;}
real 0m3.002s
user 0m0.000s
sys 0m0.000s
user
user cpu . wait . user + sys
cpu .
sys
kernel cpu . ,
system call kernel .
real user + sys
multi-core cpu . 2 core cpu
, 1 , core 1 cpu
real 1 user + sys 2 .
real 1m47.363s
user 2m41.318s
sys 0m4.013s
Exit Status:
pipeline .
Keyword Commands
128
coproc
coproc [NAME] command [redirections]
coproc (coprocess) . coproc command
background stdin, stdout FD
. FD $COPROC array
>& ${COPROC[1]} , <&
${COPROC[0]} . background pid $COPROC_PID .
# background
$ coproc while read -r line; do eval expr "$line"; done
[1] 18008
$ echo "1 + 2" >& ${COPROC[1]}
$ read -r res <& ${COPROC[0]}
$ echo $res
3
$ kill $COPROC_PID
. coproc FD
.
$ mkfifo inpipe outpipe
$ exec 3<>inpipe 4<>outpipe
$ while read -r line; do eval expr "$line" > inpipe ; done < outpipe &
[1] 17647
$ echo "1 + 2" >& 4
$ read -r res <& 3
$ echo $res
3
$ kill 17647
$ exec 3>&- 4>&$ rm -f inpipe outpipe
coproc FD .
Keyword Commands
129
Keyword Commands
130
Script
Shell script
. .
1 .
command1
command2
command3
...
2 . ;
command1; command2; command3 ...
; newline . 1, 2
. command1 command2 command2
command3 .
3 .
command1 | command2 | command3
. command1 stdout command2 stdin
command2 stdout command3 stdin
command3 stdout .
4 . &&, ||
command1 && command2
&& command1 command2 command1
command2 .
command1 || command2
|| command1 command2 . command1
command2 .
Compound Commands
131
A && {
B && {
echo "A and B both passed"
} || {
echo "A passed, B failed"
}
} || echo "A failed"
Compound Commands
compgen -k | column shell
.
loop done .
if
if ... fi
case
select
while
until
for
redirection, |, & .
redirection, , & .
Compound Commands
132
if :; then
read line
echo "$line"
else
cat
fi < infile > outfile
--------------------var=1
case $var in
1)
read line
echo "$line"
;;
*)
cat ;;
esac < infile > outfile
----------------------for (( i=10; i<20; i++ )); do
read line
echo "$line"
done < infile > outfile
-----------------------------while read -r line; do
echo "${line//bananna/banana}"
done < infile > outfile
---------------------------------if ! :; then
cat
else
case $var in
*)
cat ;;
esac < dbfile2
cat
fi < dbfile1 > outfile
Conditional Constructs
if
Compound Commands
133
if test-commands; then
consequent-commands;
[elif more-test-commands; then
more-consequents;]
[else alternate-consequents;]
fi
if if , elif , else , fi then .
. if ; then ; ... fi
.
if elif [ ] , [[ ]] group
.
! logical NOT .
case
case word in [ [(] pattern [| pattern]) command-list ;;] esac
shell script case . case
.
case .
case case , in , esac case pattern) .
pattern) .
pattern) ;; .
pattern) | .
foo\ bar escape .
* ) default .
Compound Commands
134
.
shopt -s nocasematch , .
select
select name [in words ]; do commands; done
select select , in , do , done .
PS3 .
REPLY .
in words in "$@" .
enter .
Ctrl-d select loop .
select break
.
Compound Commands
135
Looping Constructs
while
while test-commands; do consequent-commands; done
while while , do , done .
.
.
Compound Commands
136
while |
cat infile | while read -r line
do
echo "$line"
done
Compound Commands
137
until
until test-commands; do consequent-commands; done
until until , do , done .
.
.
# until ...; do ...; done
# while ! ...; do ...; done .
read -p "Enter Hostname: " hostname
until ping -c 1 "$hostname"
do
sleep 60;
done
curl -O "$hostname/mydata.txt"
for
for name [ [in [words ] ] ; ] do commands; done
for for , in , do , done .
words IFS , words . name
.
in words in "$@" .
Compound Commands
138
.
$ for (( i = 0; i <= 5; i++ )) {
echo $i;
}
0
1
2
3
4
5
Compound Commands
139
Special Expressions
Shell command arg1 arg2 ... shell
. shell
escape quote
. $(( )) , (( )) , let , [[ ]] [
.
sh $(( )) .
.
C . var++ , --var , a
? b : c , ( ) , , .
$(( )) (( )) .
, 0 . ( )
Special Expressions
140
let
Special Expressions
141
$(( )) (( ))
. let .
(( i++ )) res=$(( var + 1 ))
let i++ let res=var+1
let .
. quote .
$ let var = 1 + 2
bash: let: =: syntax error: operand expected (error token is "=")
$ let var += 1
bash: let: +=: syntax error: operand expected (error token is "+=")
$ var=4
$ let "var++, res = (var == 5 ? 10 : 20)"; echo $res
10
$ let "2 < 1"; echo $?
1
help let .
[[ ... ]]
[ . [
. pattern regex
.
[ .
[[ ]] ( = ) , pattern ( = ) , regex ( =~ )
Special Expressions
142
&& , || .
shell .
if [[ test1 && test2 ]]; then ...
if [[ test1 || test2 ]]; then ...
if [[ test1 && test2 || test3 ]]; then ...
-----------------------------------------$ [[ 1 -eq 1 || 1 -eq 2 && 1 -eq 2 ]]; echo $? # &&
0
$ [[ ( 1 -eq 1 || 1 -eq 2 ) && 1 -eq 2 ]]; echo $? # '( )'
1
$ [[ 1 -eq 1 ]] || [[ 1 -eq 2 ]] && [[ 1 -eq 2 ]]; echo $?
1
BASH_REMATCH
=~ regex ( ) .
Special Expressions
143
#!/bin/bash
regex=$1
string=$2
if [[ $string =~ $regex ]]; then
echo "$string matches"
i=0
n=${#BASH_REMATCH[@]}
while [[ $i -lt $n ]]
do
echo " capture[$i]: ${BASH_REMATCH[$i]}"
let i++
done
else
echo "$string does not match"
fi
################## ###################
$ ./regex1.sh 'a(b{2,3})([xyz])c' aabbxcc
aabbxcc matches
capture[0]: abbxc
capture[1]: bb
capture[2]: x
)
shell keyword [[ ]], IFS , read , BASH_REMATCH
regex shell .
Special Expressions
144
[ ] , [[ ]] quote
O : ( "$var" ) , X : ( $var )
unary
[ ]
[[ ]]
X , O
regex
quote
Special Expressions
145
Shell Metacharacters
Shell script .
.
.
escape quote
.
C++ ,
Makefile cmake, qmake
make . shell
.
( ) ` && || & | ;
< > >> # redirection
* ? [ ] # glob
" ' # quote
\ $
= += #
( )
subshell
$( )
grouping
;
.
`
backtick $( ) .
&& ||
Shell Metacharacters
146
AND, OR .
shell [[ ]] .
shell && || .
&
background .
; ;
.
command1 &; command2 & # error
command1 & command2 & # OK
{ ... command & ;} # error
{ ... command & } # OK
|
.
|& stdout, stderr 2>&1 | .
noclobber), << (here document) , <<- (no leading tab) , <<< (here string)
;
.
;; case pattern) .
* ? [ ]
glob .
Shell Metacharacters
147
" '
quote .
space quote .
\
escape .
$
, , .
= +=
. += sh .
escape .
&
# background process
$ find . -name foo&bar.txt
[1] 16962
bar.txt: command not found
[1]+ Done
# .
$ find . -name foo\&bar.txt
$ find . -name foo"&"bar.txt
$ find . -name foo'&'bar.txt
$ find . -name "foo&bar.txt"
$ find . -name 'foo&bar.txt'
Shell Metacharacters
148
shell .
.
# '( )'
$ (true)&&(true;false); echo $?
$ 1
# '{ }'
$ (true)&&{true;false;}; echo $?
bash: syntax error near unexpected token `}'
{ } shell keyword
{ } , , , brace
Shell Metacharacters
149
#
$AA, ${AA}, ${AA:-0}, ${AA//Linux/Unix}
#
{ echo 1; echo 2; echo 3 ;} # shell keyword
#
f1() { echo 1 ;}
# brace
echo file{1..5}
--------------------------# find
$ find . -name '*.o' -exec rm -f {} \;
logical NOT ,
! command history .
logical NOT
$ true; echo $?
0
$ ! true; echo $? # logical NOT
1
$ if true; then echo 111; else echo 222; fi
111
$ if ! true; then echo 111; else echo 222; fi
222
--------------------------------------------# logical NOT
# [, test, find .
$ [ ! 1 -eq 1 ] ...
$ if test ! 2 -eq 3; then ...
$ find . ! -name "*.o" ...
command history
! history .
Shell Metacharacters
150
$ !comp # history
compgen -k | column
$ echo "hello!516world" # double quotes history !
hellocompgen -k | columnworld
+= .
+= array . ( sh
. )
Shell Metacharacters
151
Shell Metacharacters
152
f1() {
echo arg1 : $1
echo arg2 : $2
echo arg3 : $3
}
$ f1 11 , 22 , 33
arg1 : 11
arg2 : , # ',' .
arg3 : 22
------------------$ ARR=(11,22,33)
$ echo ${AA[0]}
11,22,33
$ echo ${AA[1]}
$ echo ${AA[2]}
Shell Metacharacters
153
Metacharacters Precedence
&& , ||
Shell script && , || .
&& || shell .
a || b && c
a true .
c/c++, java
( a ) || ( b && c )
shell
( a || b ) && c
a, c
a shell ( a || b )
true ( true && c ) c .
Redirection
.
> z1, z2 echo z2
.
$ echo foobar > z1 > z2
$ cat z1
$ cat z2
foobar
{ ;} , ( ) .
z1, z2 echo z1 .
Precedence
154
redirection .
$ echo hello | cat
hello
$ echo hello | cat <<< "world"
world
Shell { ;} , ( ) . ( )
subshell { ;} .
$ true || true && false ; echo $?
1
$ true || { true && false ;} ; echo $?
0
$ true || ( true && false ) ; echo $?
0
Precedence
155
4 . Word splitting
5 . Pathname expansion (globbing)
globbing .
( )
156
Brace Expansion
Brace . brace
start , end range ( ).
string list "$AA" or ${AA} .
brace double quotes .
String lists
{string1,string2,...,stringN}
, , , . string
quote .
# ',' .
$ echo {hello}
{hello}
# ',' , .
$ echo X{apple, banana, orange, melon}Y
X{apple, banana, orange, melon}Y
# string quote .
$ echo X{apple,"ban ana",orange,melon}Y
XappleY Xban anaY XorangeY XmelonY
Preamble postscript .
Brace Expansion
157
null
$ echo -v{,,,,,}
-v -v -v -v -v -v
$ echo b{,,,A}a
ba ba ba bAa
$ cp test.sh{,bak}
$ ls
test.sh test.sh.bak
$ ls shell/{,BB/}rc.d
shell/rc.d
...
shell/BB/rc.d
...
Brace Expansion
158
$ AA=hello
# {a,b}$AA a$AA b$AA .
$ echo {a,b}$AA
ahello bhello
# $AA X$AAY "$AA" ${AA} .
$ echo X{apple,"$AA",orange,melon}Y
XappleY XhelloY XorangeY XmelonY
Ranges
{< START >...< END > }
{< START >...< END >...< INCR >}
Brace . start, end
.
$ a=1 b=10
$ echo {$a..$b} # brace .
{1..10}
start, end .
$ echo {5..12}
5 6 7 8 9 10 11 12
$ echo {c..k}
c d e f g h i j k
$ echo {5..k} # .
{5..k}
######## Increment ########
$ echo {1..10..2}
1 3 5 7 9
$ echo {10..1..2}
10 8 6 4 2
$ echo {a..z..3}
a d g j m p s v y
zero
Brace Expansion
159
$ echo {01..10}
01 02 03 04 05 06 07 08 09 10
$ echo {0001..5}
0001 0002 0003 0004 0005
# img001.png ~ img999.png
printf "%s\n" img{00{1..9},0{10..99},{100..999}}.png
# 01 ~ 10
$ for i in 0{1..9} 10; do printf "%s\n" "$i"; done
Preamble postscript .
$ echo 1.{0..9}
1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9
$ echo __{A..E}__
__A__ __B__ __C__ __D__ __E__
$ echo {A..Z}{0..9}
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 C0 C1 C2 C3 C4 C5 C6
C7 C8 C9 D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 F0 F1 F2 F3
F4 F5 F6 F7 F8 F9 G0 G1 G2 G3 G4 G5 G6 G7 G8 G9 H0 H1 H2 H3 H4 H5 H6 H7 H8 H9 I0
I1 I2 I3 I4 I5 I6 I7 I8 I9 J0 J1 J2 J3 J4 J5 J6 J7 J8 J9 K0 K1 K2 K3 K4 K5 K6 K7
K8 K9 L0 L1 L2 L3 L4 L5 L6 L7 L8 L9 M0 M1 M2 M3 M4 M5 M6 M7 M8 M9 N0 N1 N2 N3 N4
N5 N6 N7 N8 N9 O0 O1 O2 O3 O4 O5 O6 O7 O8 O9 P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 Q0 Q1
Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 S0 S1 S2 S3 S4 S5 S6 S7 S8
S9 T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 U0 U1 U2 U3 U4 U5 U6 U7 U8 U9 V0 V1 V2 V3 V4 V5
V6 V7 V8 V9 W0 W1 W2 W3 W4 W5 W6 W7 W8 W9 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 Y0 Y1 Y2
Y3 Y4 Y5 Y6 Y7 Y8 Y9 Z0 Z1 Z2 Z3 Z4 Z5 Z6 Z7 Z8 Z9
{ } , nesting .
$ echo {{A..Z},{a..z}}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y
Brace Expansion
160
Range ?
eval range .
$ a=1 b=5
$ eval echo {$a..$b} # eval .
1 2 3 4 5
$ eval echo img{$a..$b}.png
img1.png img2.png img3.png img4.png img5.png
Brace ?
{ or } escape .
$ echo \{a..c}
{a..c}
$ echo {a..c\}
{a..c}
Brace Expansion
161
Tilde Expansion
~ . double quotes .
Home
~ . $HOME .
~USERID USERID .
$ echo ~ # .
/home/bashhacker
$ echo ~man # 'man' .
/var/cache/man
~+ $PWD .
~- $OLDPWD .
Tilde Expansion
162
Parameter Expansion
(
parameter ) ( variable )
.
.
.
shell script
. sh substring expansion, search and replace, indirection, case
modification .
AA=cde AA 'cde' .
$ . AA
String length
${#PARAMETER}
# . array @ , *
.
$ AA="hello world"
$ echo ${#AA}
11
Parameter Expansion
163
Array
$ BB=( Arch Ubuntu Fedora Suse )
$ echo ${#BB[1]} # [1] Ubuntu
6
$ echo ${#BB[@]} # array BB
4
Substring expansion
${PARAMETER:OFFSET}
${PARAMETER:OFFSET:LENGTH}
. offset length
. offset 0 length .
offset length
length . offset
:- ( ) .
AA="Arch Linux Ubuntu Fedora"
$ echo ${AA:11}
Ubuntu Fedora
$ echo ${AA:11:6}
Ubuntu
$ echo ${AA:(-6)}
Fedora
$ echo ${AA:(-6):2}
Fe
$ echo ${AA:(-6):-2}
Fedo
Array
$ ARR=(11 22 33 44 55)
$ echo ${ARR[@]:2}
33 44 55
$ echo ${ARR[@]:1:2}
22 33
Positional parameters
Parameter Expansion
164
$ set -- 11 22 33 44 55
$ echo ${@:3}
33 44 55
$ echo ${@:2:2}
22 33
Substring removal
${PARAMETER#PATTERN}
${PARAMETER##PATTERN}
${PARAMETER%PATTERN}
${PARAMETER%%PATTERN}
. #
% .
longest match shortest match .
AA="this.is.a.inventory.tar.gz"
$ echo ${AA#*.} # shortest match
is.a.inventory.tar.gz
$ echo ${AA##*.} # longest match
gz
$ echo ${AA%.*} # shortest match
this.is.a.inventory.tar
$ echo ${AA%%.*} # longest match
this
#
AA="/home/bash/bash_hackers.txt"
$ echo ${AA%/*} #
/home/bash
$ echo ${AA##*/} #
bash_hackers.txt
Parameter Expansion
165
${PARAMETER/PATTERN/STRING}
${PARAMETER//PATTERN/STRING}
${PARAMETER/PATTERN}
${PARAMETER//PATTERN}
. // /
. . array[@]
.
$ AA="Arch Linux Ubuntu Linux Fedora Linux"
$ echo ${AA/Linux/Unix} # Arch Linux .
Arch Unix Ubuntu Linux Fedora Linux
$ echo ${AA//Linux/Unix} # Linux Unix
Arch Unix Ubuntu Unix Fedora Unix
$ echo ${AA/Linux} # .
Arch Ubuntu Linux Fedora Linux Suse Linux
$ echo ${AA//Linux}
Arch Ubuntu Fedora Suse
----------------------------------------$ AA="Linux Ubuntu Linux Fedora Linux"
$ echo ${AA/#Linux/XXX} # '#Linux'
XXX Ubuntu Linux Fedora Linux
$ echo ${AA/%Linux/XXX} # '%Linux'
Linux Ubuntu Linux Fedora XXX
Array[@] .
$ AA=( "Arch Linux" "Ubuntu Linux" "Fedora Linux" )
$ echo ${AA[@]/u/X} # Ubuntu Linux 'u'
Arch LinXx UbXntu Linux Fedora LinXx
$ echo ${AA[@]//u/X} #
Arch LinXx UbXntX LinXx Fedora LinXx
Parameter Expansion
166
${AA:-linux} : AA . AA , null
linux .
${AA-linux} : AA . AA linux
. AA null .
WORD .
$ AA=hello
$ echo ${AA:-linux} # AA AA
hello
$ echo ${AA-linux}
hello
$ unset AA
$ echo ${AA:-linux} # AA unset
linux # linux .
$ echo ${AA-linux}
linux
$ AA=""
$ echo ${AA:-linux} # ':-' null linux .
linux
$ echo ${AA-linux} # '-' null
# .
# WORD .
$ AA=${AA:-$(date +%Y)}
$ AA=${FCEDIT:-${EDITOR:-vi}}
Array
Parameter Expansion
167
$ AA=( 11 22 33 )
$ echo ${AA[@]:-44 55 66} # AA AA
11 22 33
$ echo ${AA[@]-44 55 66}
11 22 33
$ AA=() # unset -v AA
$ echo ${AA[@]:-44 55 66} # AA unset
44 55 66 # 44 55 66 .
$ echo ${AA[@]-44 55 66}
44 55 66
$ AA=("")
$ echo ${AA[@]:-44 55 66} # ':-' null 44 55 66
44 55 66
$ echo ${AA[@]-44 55 66} # '-' null
# .
$ AA=("" 77 88)
$ echo ${AA[@]:-44 55 66}
77 88
$ echo ${AA[@]-44 55 66}
77 88
Array[@] .
Parameter Expansion
168
$ AA=()
$ echo ${AA[@]:=11 22 33}
bash: AA[@]: bad array subscript
11 22 33
Parameter Expansion
169
Case modification
${PARAMETER^}
${PARAMETER^^}
${PARAMETER,}
${PARAMETER,,}
${PARAMETER^} : .
${PARAMETER^^} : .
${PARAMETER,} : .
Parameter Expansion
170
${PARAMETER,,} : .
$ AA=( "ubuntu" "fedora" "suse" )
$ echo ${AA[@]^}
Ubuntu Fedora Suse
$ echo ${AA[@]^^}
UBUNTU FEDORA SUSE
$ AA=( "UBUNTU" "FEDORA" "SUSE" )
$ echo ${AA[@],}
uBUNTU fEDORA sUSE
$ echo ${AA[@],,}
ubuntu fedora suse
Indirection
${!PARAMETER}
.
$ hello=123
$ linux=hello
$ echo ${linux}
hello
$ echo ${!linux} # '!linux' 'hello' .
123
Parameter Expansion
171
array .
#!/bin/bash
foo() {
echo "$1"
local ARR=( "${!2}" ) # '!2' 'AA[@]' .
for v in "${ARR[@]}"; do
echo "$v"
done
echo "$3"
}
AA=(22 33 44)
foo 11 'AA[@]' 55
################ output ###############
11
22
33
44
55
Parameter Expansion
172
Arithmetic Expansion
$(( )) , (( )) bash . sh
$(( )) . expr, bc .
,
. shell escape
. Special Expressions
array index [ ] . $[ ]
deprecated .
Arithmetic Expansion
173
Command Substitution
$( <COMMANDS> )
`<COMMANDS>`
stdout
. . backtick
.
nesting . nesting
$( ) . subshell .
$ AA=$( echo hello world )
$ echo $AA
hello world
$ AA=`pgrep -d, ibus`
$ echo $AA
17516,17529,17530,17538,17541
Quotes
globbing .
globbing double quotes
. quotes
quotes . bash $( ... )
. quotes
escape .
Command Substitution
174
# quote
$ echo $( echo "
> I
> like
> winter and snow" )
I like winter and snow
# quote .
$ echo "$( echo "
> I
> like
> winter and snow" )"
I
like
winter and snow
--------------------------------# quotes .
$ echo "$(echo "$(echo "$(date)")")"
Thu Jul 23 18:34:33 KST 2015
null
null .
$ ls # a, b, c 3
a b c
# null .
$ find . -print0 | od -a
0000000 . nul . / a nul . / b nul . / c nul
# null .
$ echo -n "$(find . -print0)" | od -a
0000000 . . / a . / b . / c
newline .
Command Substitution
175
$ AA=$'hello\n'
$ echo -n "$AA" | od -a
0000000 h e l l o nl # newline .
$ AA=$(echo -n $'hello\n\n\n')
$ echo -n "$AA" | od -a
0000000 h e l l o # newline .
Command Substitution
176
Process Substitution
<( <COMMANDS> )
>( <COMMANDS> )
background
.
.
random access .
# '>( )' subshell '$$' .
$ { echo '$$' : $$ >&2 ;} > >( echo '$$' : $$ )
$$ : 504
$$ : 504
# '$BASHPID' .
$ { echo '$BASHPID' : $BASHPID >&2 ;} > >( echo '$BASHPID' : $BASHPID )
$BASHPID : 504
$BASHPID : 22037
--------------------------------------------------------------------------$ ls -l <( : )
lr-x------ 1 mug896 mug896 64 02.07.2015 22:29 /dev/fd/63 -> pipe:[681827]
$ [ -f <( : ) ]; echo $? #
1
$ [ -p <( : ) ]; echo $? # pipe
0
shell subshell FD
Process Substitution
177
>( . . . )
shell stdout subshell stdin
.
<( . . . )
subshell stdout shell stdin
.
Process Substitution
178
)
. ulimit
soft limit hard limit
.
.
$ ulimit -Sa > ulimit.Sa.out
$ ulimit -Ha > ulimit.Ha.out
$ diff ulimit.Sa.out ulimit.Ha.out
#
$ diff <( ulimit -Sa ) <( ulimit -Ha )
1c1
< core file size (blocks, -c) 0
--> core file size (blocks, -c) unlimited
8c8
< open files (-n) 1024
--> open files (-n) 65536
12c12
< stack size (kbytes, -s) 8192
--> stack size (kbytes, -s) unlimited
.
mkfifo fifo1
mkfifo fifo2
ulimit -Sa > fifo1 &
ulimit -Ha > fifo2 &
diff fifo1 fifo2
rm fifo1 fifo2
Process Substitution
179
|
subshell parent
. shell .
Process Substitution
180
i=0
sort list.txt | while read -r line; do
(( i++ ))
...
done
# parent i 0 .
echo "$i lines processed"
0 lines processed
-----------------------------------i=0
while read -r line; do
(( i++ ))
...
done < <(sort list.txt)
# while shell i .
echo "$i lines processed"
12 lines processed
| stderr
.
$ command1 2> >( command2 ... )
background .
main . main
.
Process Substitution
181
#!/bin/bash
sync1=`mktemp`
sync2=`mktemp`
# subshell ( ) >( while read -r line ... ) child process
# read .
( while read -r line; do
case $line in
aaa* ) echo "$line" >& $fd1 ;;
bbb* ) echo "$line" >& $fd2 ;;
esac
done ) \
{fd1}> >( while read -r line; do echo "$line" | sed -e 's/x/y/g'; sleep 1; done; \
rm "$sync1" ) \
{fd2}> >( while read -r line; do echo "$line" | sed -e 's/x/z/g'; sleep 2; done; \
rm "$sync2" ) \
< <( for ((i=0; i<4; i++)); do echo aaaxxx; echo bbbxxx; done; echo ooops );
echo --- end 1 --while [ -f "$sync1" -o -f "$sync2" ]; do sleep 1; done
echo --- end 2 ---
Process Substitution
182
Word Splitting
,
.
$ set -f; IFS=:
$ ARR=(Arch Linux:Ubuntu Linux:Suse Linux:Fedora Linux)
$ set +f; IFS=$' \t\n'
$ echo ${#ARR[@]} # .
5
$ echo ${ARR[1]}
Linux:Ubuntu
$AA .
$ AA="Arch Linux:Ubuntu Linux:Suse Linux:Fedora Linux"
$ set -f; IFS=:
$ ARR=( $AA )
$ set +f; IFS=$' \t\n'
$ echo ${#ARR[@]} # .
4
$ echo ${ARR[1]}
Ubuntu Linux
IFS .
Word Splitting
183
$ AA="Arch:Ubuntu:::Mint"
$ IFS=: #
$ ARR=( $AA )
$ echo ${#ARR[@]} # 5 .
5
$ echo ${ARR[1]}
Ubuntu
$ echo ${ARR[2]}
$ echo ${ARR[3]}
----------------------------------AA="Arch Ubuntu Mint"
$ IFS=' ' #
$ ARR=( $AA )
$ echo ${#ARR[@]} # IFS .
3 # 3
$ echo ${ARR[1]}
Ubuntu
$ echo ${ARR[2]}
Mint
Double quotes
AA="echo hello world"
# quote echo hello, world .
$ $AA
hello world
# quote 'echo hello world' .
$ "$AA"
echo hello world: command not found
Script
space .
find . IFS $'\n'
.
Word Splitting
184
$ ls
2013-03-19 154412.csv ReadObject.java WriteObject.class
ReadObject.class .txt WriteObject.java
.txt
----------------------------------------------$ set -f; IFS=$'\n' # IFS newline
$ for file in $(find .)
do
echo "$file"
done
.
./WriteObject.java
./WriteObject.class
./ReadObject.java
./2013-03-19 154412.csv
./ReadObject.class
./ .txt
$ set +f; IFS=$' \t\n'
Word Splitting
185
Filename Expansion
186
globbing space .
$ for file in *
> do
> echo "$file"
> done
2013-03-19 154412.csv
ReadObject.class
ReadObject.java
.txt
WriteObject.class
WriteObject.java
Globbing shell ,
-f | noglob
Filename Expansion
187
nullglob
glob .
. shopt -s
nullglob .
$ ls
2013-03-19 154412.csv ReadObject.java WriteObject.class
ReadObject.class .txt WriteObject.java
$ echo *.sh
*.sh #
$ shopt -s nullglob
$ echo *.sh
# null
# .
$ for f in *.sh; do
> cat "$f"
> done
cat: *.sh: No such file or directory
# nullglob
$ shopt -s nullglob
$ for f in *.sh; do
cat "$f"
done
----------------------------------------------# nullglob .
for f in *.log; do
[ -e "$f" ] || continue
...
done
Filename Expansion
188
null
.
$ ls
2013-03-19 154412.csv ReadObject.java WriteObject.class
ReadObject.class .txt WriteObject.java
$ array=(11 22 33)
$ shopt -s nullglob
# array[1] null
$ unset -v array[1]
$ echo ${array[1]} # unset .
22
# globbing disable quote .
$ unset -v "array[1]"
failglob
Globbing $? 1 .
$ ls
2013-03-19 154412.csv ReadObject.java WriteObject.class
ReadObject.class .txt WriteObject.java
$ echo *.sh
*.sh
$ echo $?
0
$ shopt -s failglob
$ echo *.sh
bash: no match: *.sh
$ echo $? # failglob '1' .
1
nocaseglob
, .
dotglob
Filename Expansion
189
.filename .
globstar
** recursive .
$ echo ** # ,
$ echo **/ #
$ echo **/*.sh # .sh
globasciiranges
C locale [a-c] - range ,
. [aAbBcC] . ,
.
GLOBIGNORE
shell . globbing :
.
Glob !
quote globbing .
.
unset array[12] globbing array1
unset .
Filename Expansion
190
array glob
$ AA="Arch Linux:*:Suse Linux:Fedora Linux"
$ IFS=:
$ ARR=($AA)
$ IFS=$' \t\n'
$ echo "${ARR[@]}"
Arch Linux 2013-03-19 154412.csv Address.java address.ser
ReadObject.class ReadObject.java .txt
WriteObject.class WriteObject.java Suse Linux Fedora Linux
----------------------------------------------------------$ set -f; IFS=:
$ ARR=($AA)
$ set +f; IFS=$' \t\n'
$ echo "${ARR[@]}"
Arch Linux * Suse Linux Fedora Linux
glob quote
escape set -o noglob .
globbing disable
globbing select interactive shell, non-interactive shell
default enable . interactive shell globbing ,
. globbing
Filename Expansion
191
enable
globbing disable select enable
.
globbing disable .
# 1. shebang
#!/bin/bash -f
# 2.
set -o noglob # disable
...
...
set +o noglob # enable
set -f # disable
...
...
set +f # enable
Filename Expansion
192
Redirection
.
.
.
. stdin,
stdout, stderr shell stdin,
stdout, stderr , .
FD (file descriptor)
. stdin 0 , stdout 1 , stderr 2
redirection .
default value
$ cat infile
hello
world
$ wc 0< infile 1> outfile
$ cat outfile
2 2 12
wc redirection .
redirection < , > FD (file descriptor), FD
filename .
infile FD 0 (stdin) FD 1 (stdout) outfile
outfile . <
0 > 1 .
.
Redirections
193
Redirection
< , > . .
> FD &
. FD .
# '>' '&' FD
$ wc asdfgh 2>1
$ cat 1
wc: asdfgh: No such file or directory
. redirection FD
FD & .
Redirection
redirection .
$ echo hello > /tmp/example
$ echo > /tmp/example hello
$ > /tmp/example echo hello
Redirection !
redirection . redirection
. mycomm FD 2 (stderr) FD 1 (stdout)
outfile .
Redirections
194
exec
. shell process id exec echo $$
.
Redirections
195
stdout errmessage
.
# { ;} outfile errmessage .
{ mycomm 2>&1 > outfile ;} > errmessage
$ exec 2>&1
FD 2 FD 1 . 1 outfile 2
outfile . redirection FD 1, 2 outfile .
FD 1, 2 outfile .
$ ls -l /proc/19779/fd
total 0
lrwx------ 1 mug896 mug896 64 07.06.2015 15:33 0 -> /dev/pts/11 # stdin
l-wx------ 1 mug896 mug896 64 07.06.2015 15:33 1 -> /home/mug896/tmp/outfile
l-wx------ 1 mug896 mug896 64 07.06.2015 15:33 2 -> /home/mug896/tmp/outfile
bash .
mycomm > outfile 2>&1 mycomm &> outfile
mycomm >> outfile 2>&1 mycomm &>> outfile
mycomm1 2>&1 | mycomm2 mycomm1 |& mycomm2
Script redirection
FD 0, 1, 2
. FD
- .
Redirections
196
# FD 3 1 .
exec 3>&1 # 1 3 .
exec 1> outfile # FD 1 outfile
...
...
exec 1>&3- # FD 1 3 3 (3-)
stdin redirect .
!/bin/bash
exec 3<&0 # FD 0 3
exec 0< infile # FD 0 infile ( infile )
read var1 # 2 .
read var2
echo read from infile: $var1
echo read from infile: $var2
exec 0<&3- # FD 0 3 3 (3-)
# .
read -p "enter your favorite number : " var
echo $var
stdout redirect .
#!/bin/bash
echo start-------------# FD 1 outfile . outfile
exec 3>&1 # FD 1
exec 1> outfile
echo this message will go to outfile
exec 1>&3- # FD 1
#
echo end----------------
Redirections
197
#!/bin/bash
echo start ----------------exec 3<&0 4>&1 # FD 0, 1
exec 0< infile # ( infile )
exec 1> outfile
# stdin(0) 'tr' stdout(1) .
# redirection infile outfile .
cat - | tr a-z A-Z
Redirections
198
#!/bin/bash
exec 3<&0
exec 0< infile
lines=0
while read -r line # stdin
do
echo "$line"
(( lines++ ))
done
exec 0<&3echo number of lines read : $lines
---------------------------------#!/bin/bash
exec 3< infile
lines=0
while read -r line
do
echo "$line"
(( lines++ ))
done <& 3 # 'done < <&3' .
exec 3<&echo number of lines read : $lines
---------------------------------#!/bin/bash
exec 3< infile
lines=0
while read -r line <& 3 # FD .
do
echo "$line"
(( lines++ ))
done
exec 3<&echo number of lines read : $lines
, ?
Redirections
199
redirection , FD
.
, x
$ cat x
0000000000000000
1111111111111111
x append .
ls x append sed append
. (0 X )
$ { { ls -l /dev/fd/; sed -e 's/0/X/g' ;} >> x ;} < x
$ cat x
0000000000000000
1111111111111111
total 0
lr-x------ 1 mug896 mug896 64 08.03.2015 10:06 0 -> /home/mug896/tmp/3/x
l-wx------ 1 mug896 mug896 64 08.03.2015 10:06 1 -> /home/mug896/tmp/3/x
lrwx------ 1 mug896 mug896 64 08.03.2015 10:06 2 -> /dev/pts/8
lr-x------ 1 mug896 mug896 64 08.03.2015 10:06 3 -> /proc/15885/fd/
XXXXXXXXXXXXXXXX # 0 X
1111111111111111
total X
lr-x------ 1 mug896 mug896 64 X8.X3.2X15 1X:X6 X -> /home/mug896/tmp/3/x
l-wx------ 1 mug896 mug896 64 X8.X3.2X15 1X:X6 1 -> /home/mug896/tmp/3/x
lrwx------ 1 mug896 mug896 64 X8.X3.2X15 1X:X6 2 -> /dev/pts/8
lr-x------ 1 mug896 mug896 64 X8.X3.2X15 1X:X6 3 -> /proc/15885/fd/
x . x ls
. sed
ls x .
$ { rm -f x; { ls -l /dev/fd/; sed -e 's/0/X/g' ;} >> x ;} < x
$ cat x
total 0
lr-x------ 1 mug896 mug896 64 08.03.2015 10:08 0 -> /home/mug896/tmp/3/x (deleted)
l-wx------ 1 mug896 mug896 64 08.03.2015 10:08 1 -> /home/mug896/tmp/3/x
lrwx------ 1 mug896 mug896 64 08.03.2015 10:08 2 -> /dev/pts/8
lr-x------ 1 mug896 mug896 64 08.03.2015 10:08 3 -> /proc/15951/fd/
XXXXXXXXXXXXXXXX
1111111111111111
Redirections
200
x sed .
sed -i 's/0/X/g' x sed -i
.
.
$ { rm -f x; sed -e 's/0/X/g' > x ;} < x
$ cat x
XXXXXXXXXXXXXXXX
1111111111111111
Redirection
{ ;} grouping . redirection shell
{ ;} .
.
$ { command 2 ;} 1
# FD 3 .
$ date >&3
bash: 3: Bad file descriptor
$ date >&3 3>&1
bash: 3: Bad file descriptor
# 3>&1 FD 3 .
$ { date >&3 ;} 3>&1
Sat Aug 8 03:31:05 KST 2015
rm
.
Redirections
201
redirection
redirection . color
stderr stdout .
color() (
set -o pipefail;
"$@" 2>&1 1>&3 | sed $'s/.*/\e[31m&\e[m/' >&2
) 3>&1
# 1. { ;} ( ) subshell
# pipefail .
# 2. "$@" color .
# 3. 2>&1 : stderr stdout redirect sed .
# 1>&3 : stdout fd 3 ( stdout )
# sed stdout .
# 4. sed stderr color escape .
# '\e' escape $' ' quote .
# & .
f1() {
echo 111;
echo AAA >&2;
}
$ color f1
111 # stdout
AAA # stderr
$ color date -%Y
date: invalid option -- '%' #
: "; ; ; ;"
"; ; ; ;"
Quiz
FD 1 stdout FD 2 stderr
Redirections
202
# FD
lrwx------ 1 mug896 mug896 64 07.06.2015 15:04 0 -> /dev/pts/10 # stdin
lrwx------ 1 mug896 mug896 64 07.06.2015 15:04 1 -> /dev/pts/10 # stdout
lrwx------ 1 mug896 mug896 64 07.06.2015 15:04 2 -> /dev/pts/10 # stderr
# FD 1 FD 3
$ exec 3>&1
0 -> /dev/pts/10 # stdin
1 -> /dev/pts/10 # stdout
2 -> /dev/pts/10 # stderr
3 -> /dev/pts/10 # stdout
# FD 1 FD 2
$ exec 1>&2
0 -> /dev/pts/10 # stdin
1 -> /dev/pts/10 # stderr
2 -> /dev/pts/10 # stderr
3 -> /dev/pts/10 # stdout
# FD 2 FD 3
$ exec 2>&3
0 -> /dev/pts/10 # stdin
1 -> /dev/pts/10 # stderr
2 -> /dev/pts/10 # stdout
3 -> /dev/pts/10 # stdout
# FD 3
$ exec 3>&0 -> /dev/pts/10 # stdin
1 -> /dev/pts/10 # stderr
2 -> /dev/pts/10 # stdout
################# #################
$ ( exec 3>&1 1>&2 2>&3 3>&-; date ) 2> out
$ cat out
Sat Aug 1 15:51:45 KST 2015
$ ( exec 3>&1 1>&2 2>&3 3>&-; date -%Y ) 1> out
$ cat out
date: invalid option -- '%'
Try 'date --help' for more information.
Redirections
203
File Descriptors
, pipe, socket,
OS .
file descriptor table FD
.
FD low-level FD
shell FD pipe socket
.
parent process FD child process .
File descriptor , ,
FD 0, 1, 2 FD , ,
. exec builtin ulimit n . ( sh 9 . )
FD
: <
: >
, : <>
append : >>
. FD
( FD
). FD FD .
, , FD , , FD, -
FD 3 infile
# : FD, :
# .
$ exec 3< infile
FD 4 FD 0
File Descriptors
204
# : FD, : FD
# .
# ( exec 4>&0 . )
$ exec 4<&0
FD 3
# : FD, : '-'
# .
# ( exec 3>&- . )
$ exec 3<&-
FD 3 outfile
outfile . append
>> . > , >>
.
$ exec 3> outfile
# write `l-wx------` .
$ ls -l /proc/$$/fd/3
l-wx------ 1 mug896 mug896 64 04.07.2015 10:56 /proc/9363/fd/3 -> /home/mug896/tmp/outfile
$ echo hello FD >&3
$ cat outfile
hello FD
FD 3
$ exec 3>&$ ls -l /proc/$$/fd/3
ls: cannot access /proc/9363/fd/3: No such file or directory
FD 4 infile
File Descriptors
205
FD < .
$ cat infile
111
222
333
$ read var < infile; echo $var
111
$ read var < infile; echo $var #
111
$ exec 4< infile # FD 4 infile .
$ read var <&4; echo $var # FD .
111
$ read var <&4; echo $var
222
$ read var <&4; echo $var
333
FD 4
exec 4<&-
FD 5 outfile ,
File Descriptors
206
<> .
overwrite .
.
File Descriptors
207
$ cat iofile
111
222
333
444
555
$ exec 3<> iofile
$ echo XXX >&3 # overwrite .
$ cat iofile
XXX
222
333
444
555
$ read var <&3; echo $var # 222 .
222
$ read var <&3; echo $var
333
$ echo YYY >&3 # 444 overwrite .
$ cat iofile
XXX
222
333
YYY
555
<> .
exec FD . FD
.
pipe socket .
Shell FD pipe socket
.
socket .
$ echo hello > /dev/tcp/www.google.com/80
$ ls -al /proc/$$/fd
total 0
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 0 -> /dev/pts/18
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 1 -> /dev/pts/18
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 2 -> /dev/pts/18
File Descriptors
208
FD socket .
$ exec 3<> /dev/tcp/www.google.com/80
$ ls -al /proc/$$/fd
total 0
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 0 -> /dev/pts/18
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 1 -> /dev/pts/18
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 2 -> /dev/pts/18
lrwx------ 1 mug896 mug896 64 08.19.2015 18:37 3 -> socket:[5641570]
$ echo hello >&3
$ cat <&3
HTTP/1.0 400 Bad Request
Content-Type: text/html; charset=UTF-8
Content-Length: 1419
Date: Wed, 19 Aug 2015 09:36:39 GMT
Server: GFE/2.0
...
.
$ mkfifo mypipe
$ echo hello > mypipe # reader block .
^C # Ctrl-c
$ exec 3<> mypipe # FD block .
$ echo hello > mypipe # ( )
$
File Descriptors
209
FD child process .
shell script child process parent FD .
parent , .
$ exec 3> outfile
$ ls -l /proc/$$/fd
total 0
lrwx------ 1 mug896 mug896 64 Jul 5 09:45 0 -> /dev/pts/14
lrwx------ 1 mug896 mug896 64 Jul 5 09:45 1 -> /dev/pts/14
lrwx------ 1 mug896 mug896 64 Jul 5 09:45 2 -> /dev/pts/14
l-wx------ 1 mug896 mug896 64 Jul 5 09:45 3 -> /home/mug896/tmp/outfile
$ bash -c 'ls -l /proc/$$/fd' # child process
total 0
lrwx------ 1 mug896 mug896 64 Jul 5 09:45 0 -> /dev/pts/14
lrwx------ 1 mug896 mug896 64 Jul 5 09:45 1 -> /dev/pts/14
lrwx------ 1 mug896 mug896 64 Jul 5 09:45 2 -> /dev/pts/14
l-wx------ 1 mug896 mug896 64 Jul 5 09:45 3 -> /home/mug896/tmp/outfile
File Descriptors
210
<<< , <<
Here string ( <<< ) , here document ( << ) .
echo cat . bash -c here docuemnt
stdin sh-thd-4029673544
.
sh here document .
# '<<<' shell .
$ read var <<< "here string test"
$ echo $var
here string test
<<< , <<
211
Here document
$ cat <<END > outfile
> here
> document
> END
Here document
<<< , <<
212
Here document
$ AA=$(cat <<END
> here
> document
> END # .
> )
$ echo "$AA"
here
document
while
$ while read -r line; do
> echo "$line"
> done <<END
> here
> document
> END
here
document
Leading tab
here document <<- leading tab .
<<< , <<
213
$ if true; then
> cat <<END
> here
> document
> with tab
> END
> fi
here # leading tab
document
with tab
# '<<' '<<-'
$ if true; then
> cat <<-END
> here
> document
> without tab
> END
> fi
here # leading tab
document
without tab
<<< , <<
214
Pipe
. .
: inventory.db 3
c
.
.
cat inventory.db | cut -d ':' -f 3 | grep '^c' | sort
,
. . "
" .
subshell .
Pipe
215
shell FD
shell FD (File Descriptor) . shell pid
$$ subshell subshell FD
$BASHPID . $$ shell FD
. stdout
, stdin, stdout .
stdin .
Pipe
216
grep .
# command .
# /dev/fd /proc/self/fd process .
grep() {
# FD 1 (stdout)
if [ -t 1 ]; then
command grep -n "$@"
# stdout (named, unnamed) pipe
elif [ -p /dev/fd/1 ]; then
command grep "$@"
# stdout
elif [ -f /dev/fd/1 ]; then
command grep ...
fi
}
Pipe
217
?
command1 | command2 command1
command2 . command1 command2
.
$ ps | grep ".*"
PID TTY TIME CMD
3773 pts/0 00:00:00 bash
3784 pts/0 00:00:00 ps
3785 pts/0 00:00:00 grep
ps grep grep
ps grep .
. command2
command1 .
grep .
grep pattern very-large-file | tr a-z A-Z
head grep
.
grep pattern very-large-file | head -n 1
?
$? .
.
false true
true . set -o pipefail false
false . shell PIPESTATUS array
.
process group .
process group
process group id (pgid) . jopspec
job control process group .
Pipe
218
.
# date .
$ echo "What date is it today?" | date | cat
Mon Jul 27 10:51:34 KST 2015
$ echo "What date is it today?" | { cat ; date ;} | cat
What date is it today?
Mon Jul 27 11:01:57 KST 2015
$ echo "What date is it today?" | { date; cat ;} | cat
Mon Jul 27 11:02:05 KST 2015
What date is it today?
Pipe
219
Named Pipe
|
pipe .
unnamed pipe anonymous pipe . named pipe
.
named pipe redirection
pipe .
pipe
. gzip
mysql mypipe mysql named
pipe .
$ mkfifo /tmp/mypipe
$ gzip --stdout -d dbfile.gz > /tmp/mypipe
# mysql .
mysql> LOAD DATA INFILE '/tmp/mypipe' INTO TABLE tableName;
.
$ mkfifo mypipe
$ nc -l localhost 8080 < mypipe | nc www.naver.com 80 > mypipe
named pipe | .
Pipe FIFO
Named Pipe
220
Pipe block .
FIFO mypipe exec 3<> mypipe .
pipe block .
pipe
. writer block . pipe
writer reader .
Broken pipe
writer reader pipe writer
reader Broken pipe writer .
Named Pipe
221
Reader
writer reader pipe reader
writer reader
.
# terminal 1
# writer . reader block
$ while :; do echo $(( i++ )); sleep 1; done > mypipe
# terminal 2
$ cat mypipe # reader
0
1
2
3
...
# terminal 1
# writer ctrl-c
# terminal 2
# reader .
FD pipe
broken pipe writer
reader .
Named Pipe
222
writer
reader . FD pipe
.
# FD 3 mypipe
# named pipe
# .
# .
$ exec 3<> mypipe
writer reader
$ while :; do echo $(( i++ )); sleep 1; done > mypipe &
[1] 21951
$ cat mypipe
0
1
2
3
4
^C # ctrl-c
# reader writer broken pipe .
# .
$ cat mypipe
5
6
7
8
^C
reader writer
Named Pipe
223
# terminal 1
$ while :; do echo $(( i++ )); sleep 1; done > mypipe # writer
# terminal 2
$ cat mypipe # reader
0
1
2
3
...
# terminal 1
# ctrl-c writer
# terminal 2
# writer .
# terminal 1
# writer
$ while :; do echo $(( i++ )); sleep 1; done > mypipe
# terminal 2
# writer .
4
5
6
7
...
Named Pipe
224
$ mkfifo mypipe
$ exec 3<> mypipe
# ctrl-c
$ while :; do echo -n '1'; done > mypipe
^Cbash: echo: write error: Interrupted system call
# outfile ctrl-c
$ cat mypipe > outfile
^C
# outfile 65,536
$ ls -l outfile
-rw-rw-r-- 1 mug896 mug896 65536 08.03.2015 15:33 outfile
Named Pipe
225
Pipe
. keyword coproc . coproc ,
.
Socket
unix domain socket . unix domain socket
socket
socket ip .
socket FD .
nc . ,
2 . terminal 1 nc -lU mysocket
mysocket . terminal 2 nc -U
mysocket
.
terminal 1
$ nc -lU mysocket
hello
socket
terminal 2
Named Pipe
226
$ nc -U mysocket
hello
socket
FD
computer2
Named Pipe
227
$ nc 12.34.56.78 8080
hello
internet socket
named pipe )
Job Control wait background process exit
. named pipe . FD named
pipe while read -r res
.
#!/bin/bash
trap 'rm -f $pipe_name' EXIT
pipe_name=/tmp/mypipe_$$
mkfifo $pipe_name
exec {FD}<> $pipe_name # FD named pipe
do_job() {
echo start job $i...
sleep $((RANDOM % 5))
echo ...end job $i
exit $((RANDOM % 10))
}
number_of_jobs=10
for i in $( seq 1 $number_of_jobs )
do
( trap "echo job$i ---------- exit: \$? > $pipe_name" EXIT
do_job ) &
done
i=1
while read -r res; do
echo "$res"
[ $i -eq $number_of_jobs ] && break
let i++
done < $pipe_name
echo $i jobs done !!!
Named Pipe
228
Buffering
Buffering shell java, python ,
. stream
( grep, sed, awk ...).
.
A logfile append tail
. A ERR
logfile append grep, awk
. 4096 bytes
.
$ tail -f logfile | grep ERR | awk '{ print $3 }'
. kernel kernel
. tail -f
grep
.
[] http://www.pixelbeat.org/programming/stdio_buffering/
Buffering modes
Buffering modes 3 .
Buffering
229
, . grep, sed, awk python, java, perl
.
.
grep : --line-buffered
sed : -u,--unbuffered
tail : -f
tcpdump : -l
gawk : fflush(), close()
perl : flush(), close(), $|
python : -u , flush(), close()
java : flush(), close()
.
$ tail -f logfile | grep --line-buffered ERR | awk '{ print $3 }'
. cut, tr
.
Buffering
230
stdbuf
Usage: stdbuf OPTION... COMMAND
Options
-i, --input=MODE : stdin stream buffering
-o, --output=MODE : stdout stream buffering
-e, --error=MODE : stderr stream buffering
Modes
mode L : line buffered
mode 0 : unbuffered
full buffered KB 1000, K 1024, MB 1000*1000, M 1024*1024 ... G, T, P, E, Z, Y
.
tee stdbuf override , dd, cat
i/o stream .
sed
coprocess sed background stdout
. read
.
$ coproc sed 's/^/foo/'
[1] 5907
$ echo bar >& ${COPROC[1]}
$ read -r res <& ${COPROC[0]}
^C
-u | --unbuffered .
Buffering
231
sed
sed 1q . echo 3
sed
. sed input 3
.
$ echo -e "ONE\nTWO\nTHREE\n" | { sed 1q ; sed 1q ; sed 1q ;}
ONE
-u | --unbuffered .
# sed -u
$ echo -e "ONE\nTWO\nTHREE\n" | { sed -u 1q ; sed 1q ; sed 1q ;}
ONE
TWO
# , sed -u
$ echo -e "ONE\nTWO\nTHREE\n" | { sed -u 1q ; sed -u 1q ; sed 1q ;}
ONE
TWO
THREE
sort
sort sort buffering .
.
Buffer sizes
Default Buffer sizes
ulimit -p ( 8 * 512 = 4096 )
Buffering
232
flush
full
stream close
line buffered newline
input stream
?
.
4096
4096 bytes
. 4096
4096 bytes .
1 byte 4096 bytes .
block .
block . block .
System call .
,
kernel system call . system call
user mode kernel mode context switching
cpu . system call .
Stream
input, output . file descriptor
stream .
terminal device , pipe, socket
.
Buffering
233
Buffering
234
Job Control
&
background job .
job background vi .
background process main process Ctrlc background .
.
jobspec pid
pid jobspec .
Job Control
235
jobs
jobs [-lnprs] [jobspec ...] or jobs -x command [args]
job table . -l process id . job id
+ , - jobspec %+ current job
background job %- previous job . fg
+ , - .
jobspec %% %+ .
$ jobs # vi 3
[1] Stopped vi 111
[2]- Stopped vi 222 # previous job
[3]+ Stopped vi 333 # current job ( job )
$ fg %1 # %1
$ jobs
[1]+ Stopped vi 111 # current
[2] Stopped vi 222
[3]- Stopped vi 333 # previous
$ fg %2 # %2
$ jobs
[1]- Stopped vi 111 # previous
[2]+ Stopped vi 222 # current
[3] Stopped vi 333
Job Control
236
fg
fg [jobspec]
jobspec foreground current job .
ctrl-z stopped job table + .
jobspec current job ( + job ) .
bg
bg [jobspec ...]
stopped job background running .
jobspec current job .
suspend
suspend [-f]
suspend shell SIGCONT .
login shell -f override .
disown
disown [-h] [-ar] [jobspec ...]
disown " job " . job job
table control . ,
login shell exit HUP job ( shopt
-s huponexit ). -h job table
control .
wait
wait [-n] [jobspec or pid ]
background job . jobspec pid
job, pid .
0 .
.
Job Control
237
$! background pid .
#!/bin/bash
( sleep 1; exit 3 ) &
wait $!
echo $?
########### output ###########
3
-----------------------------#!/bin/bash
( echo start process 1...; sleep 4; echo end process 1.; exit 1 ) &
( echo start process 2...; sleep 3; echo end process 2.; exit 2 ) &
( echo start process 3...; sleep 5; echo end process 3.; exit 3 ) &
wait # 3 background process .
echo exit status: $?
########### output ###########
start process 1...
start process 2...
start process 3...
end process 2.
end process 1.
end process 3.
exit status: 0 # 0
background job
. .
Job Control
238
#!/bin/bash
trap 'rm -f $tmpfile' EXIT
tmpfile=`mktemp`
do_job() {
echo start job $i...
sleep $((RANDOM % 5))
echo ...end job $i
exit $((RANDOM % 10))
}
number_of_jobs=10
for i in $( seq 1 $number_of_jobs )
do
( trap "echo job$i : exit value : \$? >> $tmpfile" EXIT
do_job ) &
done
wait
i=0
while read -r res; do
echo "$res"
let i++
done < $tmpfile
echo $i jobs done !!!
Job control
Ctrl-c
interrupt ( SIGINT ) foreground job .
Ctrl-z
suspend ( SIGTSTP ) foreground job suspend baskground
shell foreground .
Job Control
239
Output
session job .
background job redirection
.
stty tostop background job suspend
Controlling Terminal
TTY .
Double fork
Job Control
240
{ ;} ( ) & background
Job Control
241
pid pgid .
242
process ppid, pid, pgid, sid ps
pgrep , pkill process group session
.
$ ps axfo user,ppid,pid,pgid,sid,comm
$ ps axjf
jobspec pgid process group
. Ctrl-c process group .
pid child process .
ping pid child process ping
.
-------- test.sh -------#!/bin/bash
echo test.sh ... start
ping 192.168.1.1
echo test.sh ... end
------------------------# test.sh ps
$ ps j -C test.sh
PID PGID SID TTY TIME CMD
13056 13056 12676 pts/16 00:00:00 test.sh
# test.sh pid
$ kill 13056
[1]+ Terminated ./test.sh
# child process ping ppid upstart .
$ ps jf -C ping
UID PID PPID PGID SID C STIME TTY TIME CMD
mug896 13057 1091 13056 12676 0 10:39 pts/16 00:00:00 ping 192.168.1.1
pgid .
pkill -g 13056
kill -- -13056 (pgid - .)
243
$ ps j -C test.sh
PID PGID SID TTY TIME CMD
13056 13056 12676 pts/16 00:00:00 test.sh
# test.sh pgid
$ pkill -g 13056
[1]+ Terminated ./test.sh
# pgid ping .
$ ps jf -C ping
UID PID PPID PGID SID C STIME TTY TIME CMD
session id
background setsid sid, pgid
ppid init ( or upstart ) . sid controlling terminal
parent init daemon .
setsid daemon.sh > /dev/null 2>&1 < /dev/null &
: http://blog.n01se.net/blog-n01se-net-p-145.html
244
BSD .
<
has pages locked into memory (for real-time and custom IO)
is a session leader
linux OS ps .
245
S : .
R : ps af R .
+ : interactive bash shell ps af foreground
.
s : interactive bash shell session leader
.
T : test.sh suspend job control stop . ctrl-z
.
Z : sub2.sh test.sh background process (defunct)
parent stop . parent
.
pid
. . child
process parent process wait system
call ( SIGCHLD ) child process
. parent process stop
.
< : pulseaudio .
N : rtkit-daemon .
l : X, pulseaudio, chrome .
246
L : locking lock .
lock paging, swapping unlock
latency .
D : D ( uninterruptible sleep ) S ( interruptible sleep ) sleep
signal . kill .
I/O
[] : ps COMMAND
/proc/<pid>/cmdline /proc/<pid>/stat
[ ] .
247
TTY
.
, ,
,
/dev /dev/tty* , /dev/pts/* ,
, , xterm gnometerminal emulation , telnet, ssh
.
, punch card , .
.
.
Operating System .
TTY
248
Morse teletypewriter .
TTY
249
Teletypewriter
. ,
. ,
command line interface . /dev tty
TeleTYpe .
TTY
250
2 teletypewriter
CRT . ,
dumb terminal (cpu, ram, disk ).
ethernet
.
TTY
251
,
1.
TTY
252
[] http://www.linusakesson.net/programming/tty/
VT100 . getty
login prompt .
/dev/ttyS[] .
UART driver
bytes parity checks flow control .
Line discipline
. OS baskspace,
erase word, clear line, reprint default discipline . (
readline curses raw mode
. )
line editing default discipline line
discipline ( managing packet switched data (ppp, IrDA, serial mice) )
.
[ line discipline ]
TTY driver
TTY
253
2. virtual console
[] http://www.linusakesson.net/programming/tty/
Ctrl-Alt-F1 ~ F6 OS .
TTY
254
[] http://www.linusakesson.net/programming/tty/
virtual console emulation , TTY driver
session management line discipline
emulation PTY ( Pseudo TTY ) .
PTY master/slave pair /dev/ptmx open pseudo terminal
master (PTM) file descriptor pseudo terminal slave (PTS)
device /dev/pts/ . ptm pts open /dev/pts/[]
. ptm write pts
input , pts write ptm input . kernel
named pipe .
TTY
255
[] http://rachid.koucha.free.fr/tech_corner/pty_pdip.html
telnet ssh telnet stdin, stdout, stderr
ls telnet
telnetd ptm, pts bash . pts,
ptm telnetd telnet
.
Controlling Terminal
TTY
256
. ctty ? .
job control .
TTY
257
/dev/tty
/dev/tty controlling terminal . ctty
TTY
258
$ tty
/dev/pts/1
$ stty -a
speed 38400 baud; rows 13; columns 93; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O;
min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany
imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
Control Keys
^ .
TTY
259
Ctrl
^M
^C (intr)
^D (eof)
cat, wc (
End Of File ) . ( master side
signal )
^\ (quit)
^S (stop)
^Q (start)
DEL or ^? (erase)
^U
( )
^Z (susp)
TTY
260
# terminal 1
# device : /dev/pts/1
# shell pid : 123
# file descriptor : /proc/123/fd/0 -> /dev/pts/1
# terminal 1
$ read line # stdin .
# terminal 2
$ echo hello > /proc/123/fd/0
# terminal 1
$ echo $line # .
f1 . stdout,
stderr echo -en "\e[31m"; echo 111; date; echo 222; echo -en
"\e[m"; terminal device .
,
. device
race condition .
redirection shell
.
TTY
261
HUP
HUP (hangup) .
, remote login ,
shell HUP . interactive shell HUP
stopped, running job HUP .
TTY
262
Mutual Exclusion
Shell (concurrency)
.
. shell .
. .
crontab script.sh .
script.sh
.
.
#!/bin/bash
lockfile="/var/lock/$(basename "$0")"
if [ -f "$lockfile" ]; then
# lockfile .
# exit .
exit 1
fi
# lockfile .
# lockfile .
touch "$lockfile"
# lockfile .
trap 'rm -f "$lockfile"' EXIT
command1 ...
command2 ...
command3 ...
lockfile
exit .
crontab .
Mutual Exclusion
263
. lockfile
lockfile . A
.
shell mkdir . mkdir
.
#!/bin/bash
lockfile="/var/lock/$(basename "$0")"
if ! mkdir "$lockfile" 2> /dev/null; then
exit 1
fi
trap 'rmdir "$lockfile"' EXIT
command1 ...
command2 ...
command3 ...
flock
.
1. tasks.txt task id .
2. worker.sh tasks.txt task id ,
.
3. task id .
4. task id 2 .
( task . )
task id worker.sh
task id .
task id tasks.txt
. A tasks.txt task id
B task id .
task id ,
. mkdir A
B task id .
A B A
. flock .
Mutual Exclusion
264
flock .
#!/bin/bash
lockfile="/var/lock/$(basename "$0")"
tasks_file="tasks.txt"
read_task_id() { ... ;}
delete_task_id() { ... ;}
do_task() { ... ;}
get_task_id () # critical section
{
flock 9 # file descriptor lock
local task_id
task_id=$(read_task_id); # 1. task id
if [ -n "$task_id" ]; then # 2. task id
delete_task_id #
echo "$task_id" #
else
exit 0 # 3. task id
fi
} 9> "$lockfile" # lock file descriptor
while true; then
do_task "$(get_task_id)" # do_task
done
core 4 cpu 4
do_task get_task_id
. get_task_id
critical section . tasks.txt
4 .
get_task_id .
get_task_id ()
{
exec 9> "$lockfile"
flock 9
...
...
}
Mutual Exclusion
265
flock -u unlock .
critical section .
get_task_id ()
{
command ...
...
flock 9
...
# flock critical section
...
flock -u 9
...
...
} 9> "$lockfile"
flock
flock file descriptor .
flock lock
. lock file descriptor
.
Mutual Exclusion
266
# flock 1
# flock [options] <file>|<directory> <command> [<argument>...]
# .
# .
$ flock [option] /var/lock/mylock ./script.sh 11 22 33
# flock 2
# flock [options] <file>|<directory> -c <command>
# -c command string .
# child process export -f .
$ export -f func1
$ flock [option] /var/lock/mylock -c 'func1 11 22 33'
mkdir flock
crontab .
-n fail return .
flock -n /var/lock/mylock ./script.sh
Lock propagation
crontab script.sh . script.sh
.
script.sh .
background lock .
cron job flock script.sh .
child process lock flock o .
lockfile
flock file descriptor lock
. (lockfile) A, B, C
lockfile file descriptor lock
.
Mutual Exclusion
267
lock lockfile
lock
trap lockfile .
lockfile flock
.
# lockfile /tmp
flock [option] /tmp command ...
# lockfile /dev/null
exec 9> /dev/null
flock 9
...
...
# lockfile
# '>'
# '<' append '>>' .
exec 9< "$0"
flock 9
...
...
# .
# flock '-n' (nonblock)
# fail return .
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -n "$0" "$0" "$@" || :
Mutual Exclusion
268
Signal sending
.
. .
OS PCB (Process Control Block)
.
269
OS 5 .
( new ) ready queue ( ready )
( running ). I/O wait wait() system call
waiting scheduled out . I/O, wait ready
scheduled . running
interrupt ready running
. exit( terminate ) .
270
Signal receiving
PCB
signal handler .
waiting signal sending ready .
sending receiving PCB
handler pending
count . handler
shell handler block .
signal handler
.
background SIGCHLD trap
.
Signal handler
Signal signal handler . signal
default action signal handler . SIGTSTP
SIGTERM . shell trap
signal handler .
. shell
child trap , TERM
child reparent , INT child
. INT child trap
handler bash default handler sh
default handler .
INT handler
a.sh -> b.sh -> c.sh ( a.sh b.sh , b.sh c.sh )
sleep 3 foreground process group
ctrl-c INT .
271
Ignore
trap ignore child . a.sh
INT ignore b.sh, c.sh INT handler default handler
. interactive shell SIGTSTP, SIGTTIN, SIGTTOU
ignore trap .
272
# interactive shell
$ bash -i -c trap
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU
# SIGTSTP trap .
$ bash -i -c 'trap true TSTP && trap'
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU
-----------------------------------# non-interactive shell
$ bash -c trap
# SIGTSTP trap .
$ bash -c 'trap true TSTP && trap'
trap -- 'true' SIGTSTP
273
kill
kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
Signals table default
action . kill
. kill TERM .
kill . SIG
. pid jobspec .
kill -TERM 4287
kill -SIGTERM 4287
kill -s TERM 4287
kill -s SIGTERM 4287
kill -15 4287
kill -n 15 4287
kill 4287 # TERM .
kill -0 pid
kill -0 ,
kill
274
kill -TERM 0
. background
a.sh -> b.sh -> c.sh ( a.sh
b.sh , b.sh c.sh ) c.sh exit kill
-TERM $$ c.sh a.sh, b.sh background
.
kill -TERM 0 . 0 pgid
kill shell builtin shell pgid . kill -TERM
0 c.sh pgid pgid
.
# pgid TERM
kill 0
kill -TERM 0
---------------------------------# pgid INT
kill -INT 0
kill
275
trap
trap [-lp] [[arg] signal_spec ...]
.
Ctrl-c ,
.
trap
.
signal handler
trap 'myhandler' EXIT
myhandler() { ... ;}
default handler
trap
3 trap ignore signal handler
. default handler .
SIGKILL
SIGSTOP
SIGCONT
Pseudo signals
trap
276
Description
EXIT
ERR
0 .
DEBUG
RETURN
.
, source .
RETURN
trap
277
#!/bin/bash
# functrace
set -o functrace
trap 'echo return trap' RETURN
f1() {
# functrace f1
# trap 'echo f1 return trap' RETURN
echo 111
echo 222
}
echo start--f1
f1
echo end--############# output #############
start--111
222
return trap
111
222
return trap
end---
ERR, DEBUG
Debugging
EXIT ?
EXIT INT Ctrl-c INT handler
exit EXIT handler .
sh trap
sh bash pseudo signals . EXIT
bash , handler
.
( default handler )
EXIT ctrl-c .
trap
278
# .
#!/bin/sh
trap 'rm -f /tmp/file' EXIT
ctrl-c
INT , EXIT , .
#!/bin/sh
trap 'rm -f /tmp/file; exit' EXIT HUP INT QUIT TERM
279
#!/bin/bash
trap 'f1' INT
f1() {
echo "\$$ : $$, \$BASHPID : $BASHPID"
AA=200
}
AA=100
echo "\$$ : $$, \$BASHPID : $BASHPID"
echo "before interrupt : $AA"
cat
echo "after interrupt : $AA"
-------------- --------------$$ : 15528, $BASHPID : 15528
before interrupt : 100
^C$$ : 15528, $BASHPID : 15528 # handler ctrl-c
after interrupt : 200
Ctrl-c
Ctrl-c SIGINT trap .
Ctrl-c ignore
child process
process group
Ctrl-c SIGINT foreground process group
process group . A.sh B.sh
B.sh sleep . sleep
Ctrl-c A.sh, B.sh .
trap
280
trap
281
trap
282
trap
283
B.sh subshell .
subshell $$ $BASHPID .
------- A.sh ------#!/bin/bash
echo A.sh --- start
(
trap 'trap - INT; kill -INT $BASHPID' INT
ping 1.1.1.0
)
echo A.sh --- end
-------------------$ ./A.sh # Ctrl-c .
A.sh --- start
PING 1.1.1.0 (1.1.1.0) 56(84) bytes of data.
^C
--- 1.1.1.0 ping statistics --2 packets transmitted, 0 received, 100% packet loss, time 999ms
trap
284
Ctrl-c
Ctrl-c EXIT handler
.
EXIT cat Ctrl-c
. EXIT handler default INT handler
echo 111
.
$ ( trap 'echo exit : $?' EXIT; cat; echo 111 ) # EXIT
^Cexit : 0
trap handler .
$ ( trap 'exit 0' INT; cat ); echo exit : $?
^Cexit : 0
trap
285
Signals Table
Program Error Signals
Signal
DefaultAction
Description
n/a
Terminate
(core dump)
. floatingpoint exception
. ( Floating/Integer
division by zero, modulo operation by zero,
Floating/Integer overflow ... )
n/a
Terminate
(core dump)
SIGSEGV
n/a
Terminate
(core dump)
segmentation violation
. ( read-only
memory )
SIGBUS
n/a
Terminate
(core dump)
SIGABRT
Terminate
(core dump)
abort function
.
SIGTRAP
n/a
Terminate
(core dump)
,
.
SIGEMT
n/a
Terminate
(core dump)
SIGSYS
n/a
Terminate
(core dump)
system call
. system call libc
.
SIGFPE
SIGILL
Num
Termination Signals
Signals Table
286
Signal
SIGTERM
Num
15
DefaultAction
Description
Terminate
.
SIGKILL trap ignore
. signal handler
.
SIGINT
Terminate
interrupt
Ctrl-c
.
SIGQUIT
Terminate
(core dump)
Ctrl-\
core dump .
.
Terminate
.
SIGTERM, SIGINT trap ignore
.
Terminate
network,
.
daemon
restart
reload .
SIGKILL
SIGHUP
Alarm Signals
Signal
Num
DefaultAction
Description
SIGALRM
14
Terminate
SIGVTALRM
n/a
Terminate
CPU alarm or
setitimer function
.
Terminate
cpu
system call cpu
alarm or setitimer function
. code profiling
.
SIGPROF
n/a
Signals Table
287
Signal
Num
DefaultAction
Description
SIGIO
n/a
Ignore
SIGURG
n/a
Ignore
SIGPOLL
n/a
Ignore
System V SIGIO . (
)
Num
DefaultAction
Description
SIGCHLD
n/a
Ignore
SIGCONT
n/a
Continue
SIGSTOP, SIGTSTP
. (
. )
SIGSTOP
n/a
Stop
.
trap ignore .
SIGTSTP
n/a
Stop
Ctrl-z
SIGSTOP trap ignore
.
SIGTTIN
n/a
Stop
SIGTTOU
n/a
Stop
Signals Table
288
Signal
SIGPIPE
SIGLOST
Num
DefaultAction
Description
Terminate
Terminate
n/a
n/a
SIGXCPU
n/a
Terminate
SIGXFSZ
n/a
Terminate
( soft limit )
.
Miscellaneous Signals
Signal
Num
DefaultAction
SIGUSR1
n/a
Terminate
1.
SIGUSR2
n/a
Terminate
2.
SIGWINCH
n/a
Ignore
Ignore
SIGINFO
n/a
Description
Signals Table
289
Num
. POSIX standard
OS .
DefaultAction
Terminate
.
Terminate (core dump)
core .
Ignore
.
Stop
stop . ( . )
Continue
stopped . ( . )
Signals Table
290
Shell Options
Shell .
set shopt shopt bash sh
. set SHELLOPTS shopt BASHOPTS
. set .
Set
Set set -o .
enable set -o disable set +o . [ o ] enable 0 disable 1
. $- flags .
- set -- unset .
set -- 11 22 33 11 22 33 $1 $2 $3 .
#!/bin/sh
line="11:22:33"
set -f; IFS=: # globbing disable
set -- $line # IFS positional parameters
set +f; IFS=$' \t\n'
echo number of fields = $#
echo field1 = "$1"
echo field2 = "$2"
echo field3 = "$3"
-a | allexport
Shell Options
291
-B | braceexpand
Brace . .
emacs
emacs line editing .
-e | errexit
script exit . if, while, until, ||, &&
.
-E | errtrace
shell function, subshell, ERR trap .
-T | functrace
shell function, subshell, DEBUG RETURN trap .
RETURN trap source return .
-h | hashall
. .
-H | histexpand
! history . set -o history
history
history enable, disable .
ignoreeof
Shell Options
292
interactive-comments
# .
-k | keyword
command var1=val1 var2=val2 command
.
-m | monitor
job control . disable .
subshell .
CHLD signal trap .
-C | noclobber
redirection overwriting . >| overwrite
.
-n | noexec
script syntax errors checking
.
-f | noglob
globbing disable . globbing
nolog
.
-b | notify
Shell Options
293
-u | nounset
exit .
-t | onecmd
exit .
$ set -o onecmd; command1;
-P | physical
cd .
# /usr/sys /usr/local/sys symbolic link
$ cd /usr/sys; echo $PWD
/usr/sys
$ cd ..; pwd
/usr
# :
$ cd /usr/sys; echo $PWD
/usr/local/sys
$ cd ..; pwd
/usr/local
pipefail
true, false
. false false .
$ ( true | false | true ) && ( true ); echo $?
0
$ set -o pipefail
$ ( true | false | true ) && ( true ); echo $?
1
Shell Options
294
posix
POSIX .
-p | privileged
shell script set uid bash set
uid . (effective
user) , $BASH_ENV, $ENV export
SHELLOPTS, BASHOPTS, CDPATH, GLOBIGNORE
. suid effective user id
real user id .
### alice ###
alice@box:/tmp/priv$ cp /bin/bash bash
alice@box:/tmp/priv$ chmod u+s bash # suid
alice@box:/tmp/priv$ id
uid=1004(alice) gid=1005(gamers) groups=1004(alice),1005(gamers)
### bob ###
# suid euid .
bob@box:/tmp/priv$ ./bash
bash-4.3$ id
uid=1002(bob) gid=1005(gamers) groups=1002(bob),1005(gamers)
# -p euid .
bob@box:/tmp/priv$ ./bash -p
bash-4.3$ id
uid=1002(bob) gid=1005(gamers) euid=1004(alice) groups=1002(bob),1005(gamers)
-v | verbose
.
vi
vi line editing .
-x | xtrace
, , .
.
Shell Options
295
Shopt
shopt or shopt -p . enable
shopt -s , disable shopt -u .
autocd
cd .
cdable_vars
Music AA Music cd AA .
cdspell
cd transposed characters, a missing character, one
character too many .
checkhash
$PATH
hash table .
hash .
checkjobs
exit background job table stopped job
There are stopped jobs . running job
. running job .
exit stopped job running
job background .
Shell Options
296
checkwinsize
window size $LINES $COLUMNS .
cmdhist
multiple-line history
newline ; . lithist
newline .
compat31
Bash 3.1
compat32
Bash 3.2
compat40
Bash 4.0
compat41
Bash 4.1
compat42
Bash 4.2
complete_fullquote
Shell Options
297
direxpand
.
dirspell
. direxpand .
dotglob
.filename .
execfail
script exec script .
script .
expand_aliases
alias . interactive shell on non-interactive
shell off .
extdebug
debugging .
declare -F .
DEBUG trap 0
.
Shell Options
298
shopt -s extdebug
debug_trap() {
echo DEBUG MESSAGE
return 0 # return 0, 1
}
trap 'debug_trap' DEBUG
echo HELLO 1
echo HELLO 2
echo HELLO 3
################## return 0 #################
DEBUG MESSAGE
HELLO 1 # debug message
DEBUG MESSAGE
HELLO 2
DEBUG MESSAGE
HELLO 3
################## return 1 #################
DEBUG MESSAGE
DEBUG MESSAGE #
DEBUG MESSAGE
extglob
Globbing extended pattern matching .
extquote
Parameter expansion $'string' and $"string" .
.
Shell Options
299
failglob
force_fignore
$FIGNORE : filename completion
globstar
** recursive .
$ echo ** # ,
$ echo **/ #
$ echo **/*.sh # .sh
globasciiranges
C locale [a-c] - range ,
. [aAbBcC] . ,
.
gnu_errfmt
shell "standard GNU error message format" .
histappend
Shell Options
300
histreedit
! history
.
histverify
! history
enter .
hostcomplete
/etc/hosts completion .
huponexit
interactive login shell exit jobs HUP .
interactive_comments
# .
lastpipe
| subshell
. lastpipe |
shell . job control
disable . non-interative shell script disable .
# echo hello, read var subshell echo $var .
$ echo hello | read var
$ echo $var
$
$ set +o monitor # job control disable
$ shopt -s lastpipe
# read var shell echo $var .
$ echo hello | read var ; echo $var
hello
Shell Options
301
lithist
history multiple-line newline .
login_shell
readonly login shell .
mailwarn
"The mail in mailfile has been
read" .
no_empty_cmd_completion
empty line $PATH .
nocaseglob
globbing , .
nocasematch
, .
nullglob
progcomp
. .
promptvars
, , ,
quote . .
restricted_shell
bash restricted shell readonly .
Shell Options
302
shift_verbose
shift shift count positional parameters
.
sourcepath
source $PATH . .
xpg_echo
echo single, double quotes escape sequences
.
Shell Options
303
HOME
IFS
Internal Field Separator. ( word splitting ) .
read , array
. space, tab, newline 3 IFS unset .
IFS null .
$ echo -n "$IFS" | od -a
0000000 sp ht nl
MAIL
$MAILPATH mailbox maildir
MAILPATH
mailbox : .
Shell Variables
304
OPTARG
getopts .
OPTIND
getopts index .
PATH
: .
PS1
Default interaction prompt .
.
# \u
# \h
# \w
bash-3.2$ export PS1="\u@\h \w> "
ramesh@dev-db ~> cd /etc/mail
ramesh@dev-db /etc/mail>
PS2
Continuation interactive prompt . .
# PS2 '>' .
ramesh@dev-db ~> myisamchk --silent --force --fast --update-state \
> --key_buffer_size=512M --sort_buffer_size=512M \
> --read_buffer_size=4M --write_buffer_size=4M \
> /var/lib/mysql/bugs/*.MYI
Bash Variables
BASH
shell .
Shell Variables
305
BASHOPTS
shopt : .
BASHPID
bash process id . subshell .
BASH_ALIASES
alias associative array .
BASH_ARGC
shopt -s extdebug call stack
BASH_ARGV
shopt -s extdebug call stack
array . func1 11
func2 22 33 ${BASH_ARGV[@]} 33 22 11 .
BASH_CMDS
hash builtin associative array .
hash .
BASH_COMMAND
.
$ trap 'echo \"$BASH_COMMAND\" . : $?' ERR
$ asdfgh
asdfgh: command not found
"asdfgh" . : 127
BASH_COMPAT
Bash compatibility level . .
Shell Variables
306
BASH_ENV
interactive shell .bashrc .
non-interactive shell .
.bashrc .
BASH_EXECUTION_STRING
bash -c .
BASH_LINENO
caller call stack array . a()
10 b() b() 20 c()
${BASH_LINENO[0]} caller 20 ${BASH_LINENO[1]} 10
. ${BASH_SOURCE[$i+1]} caller .
BASH_REMATCH
BASH_SOURCE
source stack array .
AA.sh BB.sh source BB.sh CC.sh source
${BASH_SOURCE[0]} CC.sh ${BASH_SOURCE[1]} BB.sh ... .
BASH_SUBSHELL
subshell .
$ echo $BASH_SUBSHELL
0
$ (echo $BASH_SUBSHELL;(echo $BASH_SUBSHELL))
1
2
BASH_VERSINFO
bash array .
Shell Variables
307
BASH_VERSION
bash .
BASH_XTRACEFD
xtrace FD (file descriptor) . set -o xtrace
xtrace stderr .
xtrace FD
.
-------------- test.sh --------------#!/bin/bash
exec 3> xtrace.txt # FD 3 xtrace.txt
BASH_XTRACEFD=3 # trace FD 3
set -x
date -%Y # error
AA=100
BB=200
CC=`expr $AA + $BB`
date -%Y # error
set ---------------------------------------# stderr
$ ./test.sh
date: invalid option -- '%'
Try 'date --help' for more information.
date: invalid option -- '%'
Try 'date --help' for more information.
$ cat xtrace.txt
+ date -%Y
+ AA=100
+ BB=200
++ expr 100 + 200
+ CC=300
+ date -%Y
+ set -
CHILD_MAX
child process .
Shell Variables
308
COLUMNS
. select .
COMP_CWORD
index ${COMP_WORDS[COMP_CWORD]} .
COMP_LINE
.
COMP_POINT
index . ${#COMP_LINE} .
COMP_TYPE
completion type .
COMP_KEY
completion .
COMP_WORDBREAKS
. unset
. .
0000000 sp " ' > < = ; | & ( :
20 22 27 3e 3c 3d 3b 7c 26 28 3a
COMP_WORDS
array .
COMPREPLY
Shell Variables
309
array tab
.
COPROC
coproc builtin file descriptors array .
DIRSTACK
array . dirs builtin
.
EMACS
shell t emacs shell buffer
line editing disable .
ENV
$BASH_ENV . shell POSIX .
EUID
numeric effective user id readonly . set uid
FCEDIT
fc -e .
FIGNORE
: filename completion . )
.o:.class
FUNCNAME
call stack array . a() b()
b() c() ${FUNCNAME[0]} c()
${FUNCNAME[1]} b() ... .
Shell Variables
310
FUNCNEST
maximum function nesting level . nesting level
.
GLOBIGNORE
globbing : .
GROUPS
array .
HISTCMD
history number .
HISTCONTROL
history : .
ignorespace : space history .
ignoredups : history .
ignoreboth : ignorespace:ignoredups .
erasedups : history history .
HISTFILE
history .
HISTFILESIZE
history .
HISTIGNORE
history : .
HISTSIZE
history . 500 .
Shell Variables
311
HISTTIMEFORMAT
history timestamp . history file . ) export
HISTTIMEFORMAT="%Y%m%d %T "
HOSTFILE
/etc/hosts hostname completion .
HOSTNAME
.
HOSTTYPE
. ) x86_64
IGNOREEOF
set -o ignoreeof ctrl-d (EOF)
exit .
INPUTRC
Readline . ~/.inputrc .
LANG
LC_ .
LC_ALL
LC_ LANG overriding .
LC_COLLATE
sorting the results of filename expansion, and determines the behavior of range expressions,
equivalence classes, and collating sequences within filename expansion and pattern
matching .
LC_CTYPE
Shell Variables
312
LC_MESSAGES
$" " .
LC_NUMERIC
number formatting .
LINENO
Script shell function .
LINES
. select .
MACHTYPE
GNU cpu-company-system format .
MAILCHECK
.
MAPFILE
mapfile .
OLDPWD
cd .
OPTERR
getopts 0 .
1 . getopts
.
OSTYPE
Shell Variables
313
shell OS . ) linux-gnu
PIPESTATUS
array.
POSIXLY_CORRECT
export POSIXLY_CORRECT=t bash process posix mode . shell
set -o posix posix mode .
PPID
shell parent process id readonly .
PROMPT_COMMAND
PS1 .
PROMPT_DIRTRIM
... .
PS3
select .
PS4
-x | set -o xtrace
, . PS4
. + .
Shell Variables
314
# PS4
export PS4='+(${BASH_SOURCE[0]}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
PWD
cd .
RANDOM
0 ~ 32767 random number .
READLINE_LINE
readline script
.
READLINE_POINT
readline script
index .
REPLY
read .
SECONDS
shell script
. .
SHELL
.
SHELLOPTS
set : .
SHLVL
Shell Variables
315
TIMEFORMAT
time .
TMOUT
read , select .
.
exit .
TMPDIR
shell .
UID
numeric real user id readonly . login id
.
Shell Variables
316
Positional Parameters
function
source
positional paramters .
$1 , $2 ... scope local . sh
array .
$0
.
bash -c .
$#
$0 .
Positional Parameters
317
$@ , $*
$@ , $* positional parameters . array @ , *
. quote
quote "$@" "$1" "$2" "$3" ... "$*"
"$1c$2c$3 ... " . ( c IFS . )
Positional Parameters
318
set
set shell positional paramters
.
set -- 11 22 33 set - 11 22 33
$1 $2 $3 11 22 33 .
set --
positional parameters .
Positional Parameters
319
shift
shift [n]
shift positional parameters n .
n positional parameters .
$ set -- 11 22 33 44 55
$ echo $@
11 22 33 44 55
$ shift 2
$ echo $@
33 44 55
$IFS
$IFS set .
Positional Parameters
320
#!/bin/sh
line="11:22:33:44:55"
set -f; IFS=: # globbing disable
set -- $line # IFS positional parameters
set +f; IFS=$' \t\n'
echo number of fields = $#
echo field 1 = "$1"
echo field 2 = "$2"
shift 3
echo \$@ = "$@"
############# output #############
number of fields = 5
field 1 = 11
field 2 = 22
$@ = 44 55
Substring expansion
Substring expansion bash .
$ set -- 11 22 33 44 55
$ echo ${@:3}
33 44 55
$ echo ${@:2:2}
22 33
Positional Parameters
321
Special Parameters
$?
.
$$
shell process id . subshell .
$!
& background process id .
| process id .
$_
. .
Special Parameters
322
Command Aliases
.
.
. shell ,
alias .
alias alias alias .
alias cp='cp -i'
alias mv='mv -i'
alias grep='grep --color=auto'
alias p4='ps axfo user,ppid,pid,pgid,sid,tty,stat,args'
alias geturl='python /some/cool/script.py'
$ geturl http://example.com/excitingstuff.jpg
# '|' ';' '{ }' '( )' .
alias name1='command1 | command2 | command3'
alias name2='command1; command2; command3'
alias name3='{ command1; command2; command3 ;}'
shell .
non-interactive shell script disable .
( shopt -s expand_aliases .)
alias subshell .
child process .
( vi .)
alias expand .
$ alias mv='mv -i'
$ mymv() { mv "$1" "$2" ;}
$ declare -f mymv
mymv ()
{
mv -i "$1" "$2" # mv alias .
}
Command Aliases
323
alias .
alias escape \ quote .
command , builtin .
alias unalias .
Command Aliases
324
Command History
interactive shell history .
history .
history list . shopt
-s histappend $HISTFILE history list .
history history list
. . history !
! logical NOT history
.
!n
n .
$ !2145
lsb_release -d
Description: Ubuntu 15.04
$ echo command is : !2145
command is : lsb_release -d
!!
.
$ history
...
3 ps af
4 cat README.md
5 find . -type f -name *.log -size +10M -exec rm -f {} \;
$ !!
find . -type f -name *.log -size +10M -exec rm -f {} \;
!-n
Command History
325
n .
$ history
...
3 date
4 ps af
5 find . -name "*.log"
$ !-1
find . -name "*.log"
$ !-2
ps af
$ !-3
date
!string
string .
$ history
...
3 find . -type f -name *.log -size +10M -exec rm -f {} \;
4 find . -name "*.log"
5 ps af
$ !fi
find . -name "*.log"
!?string[?]
string .
.
$ history
...
3 find . -name "*.tmp" -o -name "*.old"
4 find . -name "*.tmp"
5 find . -name "*.log"
$ !?tmp
find . -name "*.tmp"
$!?tmp? -exec rm -f {} \;
find . -name "*.tmp" -exec rm -f {} \;
Command History
326
: . 0
1, 2, 3 ... .
$ !com:0 # 0
command
$ !com:1 # 1
arg1
$ !com:2 # 2
arg2
$ !com:2-4 # '-'
arg2 arg3 arg4
$ !com:* # '*' .
arg1 arg2 arg3 arg4 arg5
$ !com:3* # '3*' 3
arg3 arg4 arg5
$ !com:^ # '^' .
arg1 # !com:1 , ':' !com^ .
$ !com:$ # '$' .
arg5 # ':' !com$ .
Command History
327
$ history
...
3 date
4 ps af
5 echo 11 22 33 44
$ !:0
echo
$ !:1
11
$ !*
11 22 33 44
$ !^
11
$ !$
44
, modifiers
, : modifiers
.
s/old/new/
old new . new &
old . g
. & .
find . -name "2010-09-*.log" -o -name "2011-01-*.log"
...
#
$ !find:s/log/txt/
find . -name "2010-09-*.txt" -o -name "2011-01-*.log"
# 'g' .
$ !find:gs/log/txt/
find . -name "2010-09-*.txt" -o -name "2011-01-*.txt"
# '&' .
$ !find:g&
find . -name "2010-09-*.txt" -o -name "2011-01-*.txt"
Command History
328
cat /home/foo/bar/tmp/readme.txt
...
$ !cat:h # 'h' head
cat /home/foo/bar/tmp # cat
$ !cat:h/README
cat /home/foo/bar/tmp/README
$ !cat:1:h # ':1' head
/home/foo/bar/tmp
$ head !cat:1:h/README
head /home/foo/bar/tmp/README
$ !cat:t # 't' tail
readme.txt
$ tail !cat:t
tail readme.txt
cat /home/foo/bar/tmp/readme.txt
...
$ !cat:r # remove
cat /home/foo/bar/tmp/readme
$ !cat:r.old
cat /home/foo/bar/tmp/readme.old
$ !cat:e # (extension) .
.txt
quoting
cat a1.txt a2.txt a3.txt
...
$ !cat:q # quote .
'cat a1.txt a2.txt a3.txt'
$ !cat:x # space quote .
'cat' 'a1.txt' 'a2.txt' 'a3.txt'
Command History
329
history p
.
find . -name "*.log"
...
$ !find:s/log/tmp/:p #
find . -name "*.tmp"
History
HISTIGNORE
history : .
HISTIGNORE='ls:ls -al:cd:bg:fg:history'
HISTFILESIZE
history .
HISTSIZE
history . 500 .
HISTFILE
history .
HISTCONTROL
history : .
ignorespace : space history .
ignoredups : history .
ignoreboth : ignorespace:ignoredups .
erasedups : history history
.
HISTTIMEFORMAT
history timestamp . history file .
) export HISTTIMEFORMAT="%F %T "
Command History
330
History
Set
history
history enable, disable .
-H | histexpand
! history . set -o history
Shopt
cmdhist
multiple-line history
newline ; . lithist
newline .
lithist
multiple-line newline .
histreedit
history
.
histverify
history enter .
histappend
shell exit HISTFILE history list append .
off overwrite .
history list .
PROMPT_COMMAND='history -a' .
History builtin
history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]
Command History
331
-c
-d offset
history list .
offset .
-r
-n
history file .
-a
-w
Command History
332
Command Completion
. tab
. complete,
compgen, compopt .
.
# find 'find -' tab
# .
$ find -[tab]
-amin -fprint0 -mmin -quit
-anewer -fprintf -mount -readable
-atime -fstype -mtime -regex
-cmin -gid -name -regextype
-cnewer -group -newer -samefile
-context -help -nogroup -size
-ctime -ignore_readdir_race -noignore_readdir_race -true
-daystart -ilname -noleaf -type
-delete -iname -nouser -uid
-depth -inum -nowarn -used
-empty -ipath -ok -user
-exec -iregex -okdir -version
-execdir -iwholename -path -warn
-executable -links -perm -wholename
-false -lname -print -writable
-fls -ls -print0 -xdev
-follow -maxdepth -printf -xtype
complete builtin .
$ complete -p find
complete -F _find find # find _find
$ complete -p help
complete -A helptopic help # help helptopic action
Completion .
.
. 'hello'
.
Command Completion
333
# hello
$ completion -W "aaa bbb ccc ddd" hello
# 'hello ' tab .
$ hello [tab]
aaa bbb ccc ddd
# 'hello c' tab 'hello ccc' .
$ hello c[tab]
#
$ complete -p hello
complete -W 'aaa bbb ccc ddd' hello
-W wordlist completion
. -A action .
# export action
$ complete -A export hello
# 'hello ' tab export .
$ hello [tab]
ANT_HOME LC_ADDRESS SCALA_HOME
CDPATH LC_IDENTIFICATION SESSION
CLUTTER_IM_MODULE LC_MEASUREMENT SESSION_MANAGER
COLORTERM LC_MONETARY SESSIONTYPE
DART_SDK LC_NAME SHELL
DBUS_SESSION_BUS_ADDRESS LC_NUMERIC SHLVL
...
-A action .
Command Completion
334
action
-a | alias
alias
arrayvar
array
binding
-b | builtin
Shell builtin .
-c | command
(builtin ).
-d | directory
.
FIGNORE .
disabled
enabled
-e | export
Export shell .
-f | file
( ).
FIGNORE .
function
Shell .
-g | group
Group
helptopic
Help builtin .
hostname
/etc/hosts . (HOSTFILE ).
-j | job
Job .
-k | keyword
Shell .
running
Running jobs .
-s | service
Service .
setopt
Set .
shopt
Shopt .
signal
Signal .
stopped
Stopped jobs
-u | user
User .
-v | variable
shell .
Completion Options
-o option completion
. compopt .
compopt -
+
Command Completion
335
bashdefault
default Bash completions .
$ complete -o bashdefault -W '' hello
# bash
$ hello $BASH_[tab]
$BASH_ALIASES $BASH_COMMAND $BASH_SOURCE
$BASH_ARGC $BASH_COMPLETION_COMPAT_DIR $BASH_SUBSHELL
$BASH_ARGV $BASH_LINENO $BASH_VERSINFO
$BASH_CMDS $BASH_REMATCH $BASH_VERSION
#
$ hello Read*[tab]
ReadObject.class ReadObject.java
$ hello Read*.j*[tab]
$ hello ReadObject.java #
default
readline .
# -W ''
$ complete -W '' hello
$ hello [tab] # tab .
# '-o default'
$ complete -o default -W '' hello
# readline .
$ hello [tab]
2013-03-19 154412.csv music/ video/
Address.java ReadObject.class WriteObject.class
address.ser ReadObject.java WriteObject.java
dirnames
.
$ complete -o dirnames -W '' hello
# .
$ hello [tab]
music/ video/
Command Completion
336
filenames
.
escape / .
$ complete -W 'hoo\ bar foo&bar music' hello
# .
$ hello hoo bar
$ hello foo&bar
$ hello music
# -o filenames
$ complete -o filenames -W 'hoo\ bar foo&bar music' hello
# escape
# '/' .
$ hello hoo\ bar
$ hello foo\&bar
$ hello music/
noquote
escape
disable .
#
$ ls
2013-03-19 154412.csv address.ser music/ ReadObject.java WriteObject.class
Address.java foo&bar.cvs ReadObject.class video/ WriteObject.java
# file action
$ complete -A file hello
# escape .
$ hello 2013-03-19\ 154412.csv
$ hello foo\&bar.cvs
# -o noquote
$ complete -o noquote -A file hello
# escape disable .
$ hello 2013-03-19 154412.csv
$ hello foo&bar.cvs
nospace
. .
Command Completion
337
plusdirs
.
, escape .
#
$ ls
2013-03-19 154412.csv address.ser music/ ReadObject.java WriteObject.class
Address.java foo&bar.cvs ReadObject.class video/ WriteObject.java
# -o plusdirs
$ complete -o plusdirs -W 'aaa bbb ccc' hello
# aaa bbb ccc
$ hello [tab]
aaa bbb ccc music/ video/
-G globpat
globbing .
$ complete -G "*.java" hello
$ hello [tab]
Address.java ReadObject.java WriteObject.java
-X filterpat
.
Command Completion
338
-P prefix, -S suffix
, prefix, suffix .
$ complete -W 'aaa bbb ccc' -S "/" hello
$ hello
aaa/ bbb/ ccc/
-D
default
-E
empty
-F
. script non-interactive
$1 , $2 , $3 .
Command Completion
339
.
COMP_WORDS
array .
COMP_WORDS[0]=mycomm , COMP_WORDS[1]=ubuntu , COMP_WORDS[2]=fedora ,
COMP_WORDS[3]=arch .
COMP_CWORD
index . 3 . $2
${COMP_WORDS[COMP_CWORD]} $3 ${COMP_WORDS[COMP_CWORD-1]} .
COMPREPLY
Array ,
. tab
.
compgen
. complete
. word word
. COMPREPLY
.
# word
$ compgen -W 'a111 b222 b333 c444' -- b
b222
b333
)
2 . script
shebang line ( #!/bin/bash ) .
. COMPREPLY array return .
mycomp.sh source mycomp.sh
. ~/.bash_completion
/etc/bash_completion.d/ .
Command Completion
340
complete -F hello
.
mycomp_() {
local comm=$1
local cur=$2
local prev=$3
local options="--fruit --planet --animal"
local fruits="apple orange banana"
local planets="mars jupiter saturn"
local animals="lion tiger elephant"
if [ ${COMP_CWORD} -eq 1 ]; then
COMPREPLY=( $(compgen -W "$options" -- "$cur") )
return
fi
if [ ${COMP_CWORD} -eq 2 ]; then
case $prev in
--fruit)
COMPREPLY=( $(compgen -W "$fruits" -- "$cur") )
;;
--planet)
COMPREPLY=( $(compgen -W "$planets" -- "$cur") )
;;
--animal)
COMPREPLY=( $(compgen -W "$animals" -- "$cur") )
;;
esac
return
fi
}
complete -F mycomp_ hello
Command Completion
341
Command Completion
342
Readline
CLI (command line interface) line editing, history,
shell ,
history, . line editing emacs vi
emacs set -o emacs or set -o vi
.
. window manager
.
~/.inputrc
Readline
343
# , word completion
set completion-ignore-case on
# emacs
set editing-mode emacs
# emacs
$if mode=emacs
# alt-space git
"\e ": "git "
# ctrl-space docker
"\C-@": "docker "
# \C-k\C-u kill-line(C-k), unix-line-discard(C-u) line editing
# . \C-m enter .
# F9 git pull
"\e[20~": "\C-k\C-ugit pull\C-m"
# F10 git push
"\e[21~": "\C-k\C-ugit push\C-m"
$endif
shortcut
Alt-/ .
Alt-. .
Ctrl-r history
. .
editor Ctrl-x Ctrl-e
vi editor . :wq vi
:cq .
http://readline.kablamo.org/emacs.html .
Readline wrapper
CLI readline . sqlplus,
ed line editing, history
.
Readline
344
Readline
345
Debugging
Syntax Check
-n | set -o noexec syntax errors
. syntax . typo
.
./test.sh: line 8: syntax error near unexpected token `fi'
Typo Check
-u | set -o nounset exit .
typo check . -u
Workspace .
#!/bin/bash -u
...
myTestDir=test2
...
rm -rf ~/Workspace/$myTestdir
...
################## output ####################
./test.sh: line 15: myTestdir: unbound variable
exit .
# SOME_ENV_VAR null exit .
if [ "${SOME_ENV_VAR:-}" ]; then
echo exist
else
echo null or unset
fi
,
.
Debugging
346
myfunc()
{
# $1 .
if [ -n "${1:-}" ]; then ...
# flag null 1
res=$(( ${flag:-1} + 100 ))
}
Xtrace
Xtrace , ,
. , colon :
. -x | set -o xtrace
set - set +o xtrace trace
..
xtrace [ 'too many arguments' trace .
Debugging
347
xtrace $ .
echo echo trace . colon
: . :
Debugging
348
#!/ bin/bash
set -x
for i in {25..28}; do
(( i = i * 123 ))
: i = $i, i / 2 = $(( i / 2 )) # ':'
done
set -
############## output ##############
+ for i in '{25..28}'
+ (( i = i * 123 ))
+ : i = 3075, i / 2 = 1537
+ for i in '{25..28}'
+ (( i = i * 123 ))
+ : i = 3198, i / 2 = 1599
+ for i in '{25..28}'
+ (( i = i * 123 ))
+ : i = 3321, i / 2 = 1660
+ for i in '{25..28}'
+ (( i = i * 123 ))
+ : i = 3444, i / 2 = 1722
+ set -
Xtrace stepping
Xtrace break point
stepping . DEBUG trap job control
.
https://github.com/mug896/bash-stepping-xtrace
Debugging
349
Trapping ERR
shell . -e |
set -o errexit .
. ERR trap
BASH_SOURCE, LINENO, BASH_COMMAND, $?
.
: error_command.sh
#!/bin/bash
echo --------- error_command.sh --------- start
exit 3
echo --------- error_command.sh --------- end
: trap_error.sh
-E | set -o errtrace function subshell ERR trap .
Debugging
350
#!/bin/bash -Ee
trap 'exitcode=$?; echo ERR!!! "${BASH_SOURCE[0]}": $LINENO: exit $exitcode: "$BASH_COMMAND"'
echo --------- trap_err.sh --------- start
./error_command.sh
echo --------- trap_err.sh --------- end
$ ./trap_err.sh
--------- trap_err.sh --------- start
--------- error_command.sh --------- start
ERR!!! ./trap_err.sh: 5: exit 3: ./error_command.sh
trap .
./error_command.sh
[ $? -eq 0 ] && echo true
./error_command.sh
if [ $? -eq 0 ]; then
...
ERR trap
0 false 1 .
Debugging
351
# let, (( ))
$ i=0 # i++ postfix operator 0
$ (( i++ )) # 1 .
$ echo $? # 1
1
-------------$ i=0
$ let i++ #
$ echo $?
1
-------------# expr 1 - 1 0 false .
# expr 1 .
$ foo=$(expr 1 - 1)
$ echo $?
1
Debugging
352
Dash
Dash (Debian Almquist SHell) POSIX /bin/sh shell
OS . interactive shell
script bash
start-up time boot script . (OS
shell script shell start-up time .)
http://unix.stackexchange.com/a/148061/117612 bash .
dash script . [[ ]] , (( )) ,
let bash ( bashism )
Quotes
echo echo -e . single quotes, double
quotes escape . $' ' bashism
.
sh$ AA=" \t\n" # double quotes
sh$ echo -n "$AA" | od -a
0000000 sp ht nl
sh$ AA=' \t\n' # single quotes
sh$ echo -n "$AA" | od -a
0000000 sp ht nl
$(( . . . ))
dash .
++ , --
Dash
353
**
Parameter expansion
.
Substring expansion : ${parameter:offset:length} ...
Search and replace : ${parameter/pattern/string} ...
Indirection : ${!parameter}
Case modification : ${parameter^^}, ${parameter,,} ...
[! ]
[ ] not ^ ! .
case goo in
[!f]*)
echo 'not f*'
;;
esac
Redirections
1>&3- . 1>&3 3>&-
command &> file command > file 2>&1 .
command1 |& command2 command1 2>&1 | command2 .
read
-r .
Dash
354
<<
Here document << .
File Descriptor
exec , redirection FD 9 .
read bash eval
.
# read bash
sh$ echo -n "$IFS" | od -a
0000000 sp ht nl
sh$ IFS=: read v1 v2 v3
1:2:3
sh$ echo $v1 $v2 $v3
1 2 3
sh$ echo -n "$IFS" | od -a #
0000000 sp ht nl
# eval
sh$ a=1 b=2 c=3
sh$ a=4 b=5 c=6 eval 'echo $a $b $c'
4 5 6
sh$ echo $a $b $c #
4 5 6
# script child process .
sh$ echo $a $b $c
1 2 3
sh$ a=4 b=5 c=6 bash -c 'echo $a $b $c'
4 5 6
sh$ echo $a $b $c
1 2 3
command history
dash command history . history
disable ! escape .
Bashism
Dash
355
bash dash .
+=
+= . .
Array
Array POSIX indexed array, associative array
AA=() . positional parameters
.
Dash
356
#!/bin/sh
line="11:22:33:44:55"
set -f; IFS=: # globbing disable
set -- $line # IFS positional parameters
set +f; IFS=$' \t\n'
echo number of fields = $#
echo field 1 = "$1"
echo field 2 = "$2"
shift 3
echo \$@ = "$@"
############# output #############
number of fields = 5
field 1 = 11
field 2 = 22
$@ = 44 55
'[' '=='
[ "$var1" == "$var2" ] # bashism
[ "$var1" = "$var2" ] # '='
[[ . . . ]] , (( . . . ))
for ((i=0; i<3; i++))...
bashism .
Brace expansion
Process substitution
<<<
here string .
function
Dash
357
source
source ./subscript.sh # source
. ./subscript.sh # '.'
declare
declare local .
select, disown
shopt
shopt .
$LINENO, $PIPESTATUS
$RANDOM
# $RANDOM .
random=$(awk 'BEGIN{srand(); printf "%d\n",(rand()*256)}')
Dash
358
Colors
ASCII 0x20 0x7F A B C 1 2 3
backspace control .
function . ascii
escape 0x1b (sequence)
( escape sequence )
$ od -tax1 [enter]
^[OP^[OQ^[OR^[[A^[[B # f1 ~ f3 , [enter]
0000000 esc O P esc O Q esc O R esc [ A esc [ B nl
1b 4f 50 1b 4f 51 1b 4f 52 1b 5b 41 1b 5b 42 0a
^C # ctrl-c
od function 0x1b
(esc) . escape sequence
.
1. escape
escape .
\e , \x1b (16) , \033 (8)
2. [
.
4. m
359
)
# \e echo -e .
echo -e "\e[0;31m red foreground"
echo -e "\e[0;44m blue background"
echo -e "\e[0;1m bright style"
echo -e "\e[0;31;44m red foreground, blue background"
echo -e "\e[0;1;31;44m bright style, red foreground, blue background"
# reset .
echo -e "\e[0m"
# reset .
echo -e "\e[0;1;31m ..."
Color, Style
16 color terminal . style 10 foreground
30 , background 40 .
.
360
# Style
0 Reset all attributes # reset .
1 Bright
2 Dim
4 Underscore
5 Blink
7 Reverse # foreground background .
8 Hidden # .
# Foreground
30 Black
31 Red
32 Green
33 Yellow
34 Blue
35 Magenta
36 Cyan
37 White
# Background
40 Black
41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Cyan
47 White
361
#!/bin/bash
for fgcolor in {30..37} ; do
for bgcolor in {40..47}; do
for attr in 0 1 2 4 5 7; do
echo -en "\e[${attr};${fgcolor};${bgcolor}m"
echo -n " ${attr};${fgcolor};${bgcolor} "
echo -en "\e[0m"
done
echo
done
echo
done
------------------------------------------------------#!/bin/bash
for fgcolor in {30..37} {90..97} 39 ; do
for bgcolor in {40..47} {100..107} 49 ; do
for attr in 0 1 2 4 5 7 ; do
echo -en "\e[${attr};${bgcolor};${fgcolor}m"
echo -n " ${attr};${bgcolor};${fgcolor} "
echo -en "\e[0m"
done
echo
done
done
tput
.
control characters, escape seqeunces commands .
terminfo (termcap )
( /lib/terminfo ). terminfo device
independent .
color escape sequence emulation
. Ctrl-Alt-F1 ~ F6
$TERM linux gnome-terminal xterm gnome-terminal
.
tput terminfo
.
362
# foreground color
tput setaf {color}
# background color
tput setab {color}
# Style
tput bold Set bold mode
tput dim turn on half-bright mode
tput smul begin underline mode
tput rmul exit underline mode
tput rev Turn on reverse mode
tput smso Enter standout mode (bold on rxvt)
tput rmso Exit standout mode
tput sgr0 Turn off all attributes ( '\e[0m' )
# Color
0 Black
1 Red
2 Green
3 Yellow
4 Blue
5 Magenta
6 Cyan
7 White
tput terminfo .
.
363
color_reset=$(tput sgr0)
color_f_red=$color_reset$(tput setaf 1)
color_b_blue=$color_reset$(tput setab 4)
color_s_bold=$color_reset$(tput bold)
color_my1=$color_reset$(tput setaf 1)$(tput setab 4)
color_my2=$color_reset$(tput bold)$(tput setaf 1)$(tput setab 4)
echo "$color_f_red red foreground"
echo "$color_b_blue blue background"
echo "$color_s_bold bold style"
echo "$color_my1 red foreground, blue background"
echo "$color_my2 bold style, red foreground, blue background"
echo $color_reset
# reset .
$(tput sgr0)
# reset .
$(tput sgr0)$(tput setaf 1) ...
#!/bin/bash
for fgcolor in {0..7} ; do
for bgcolor in {0..7}; do
for attr in sgr0 bold dim smul rev; do
echo -n "$(tput $attr)$(tput setaf $fgcolor)$(tput setab $bgcolor)"
echo -n " $attr;$fgcolor;$bgcolor "
echo -n "$(tput sgr0)"
done
echo
done
echo
done
Prompt
Shell $PS1 prompt .
1. prompt escape sequences
2. eval echo \""$PS1"\"
364
365
Code
Description
\a
\d
\D{format}
strftime(3) format . { }
\D{} empty
.
\e
\h
\H
the hostname
\j
background jobs
\l
\n
newline
\r
carriage return
\s
\t
( 24-hour HH:MM:SS )
\T
( 12-hour HH:MM:SS )
\@
( 12-hour am/pm )
\A
( 24-hour HH:MM )
\u
username
\v
\V
\w
\W
\!
history number
\#
command number
( enter )
\$
\nnn
\\
a backslash
\[
non-printing sequence
( color escape sequence )
\]
non-printing sequence
366
Tips
quote .
quote , globbing
. = , +=
. quote , globbing
.
$ AA="I
> like
> winter and snow"
$ echo $AA # quote .
I like winter and snow
$ BB=$AA # quote .
$ echo "$BB" # .
I
like
winter and snow
-----------------------$ ARR=(11 22 33 44 55)
$ AA=${ARR[*]} # array .
$ echo "$AA"
11 22 33 44 55
----------------------$ AA=* # globbing .
$ echo "$AA"
*
. read IFS
IFS .
Tips
367
.
. echo $A $B $C
.
$ A=1 B=2 C=3
$ A=4 B=5 C=6 echo $A $B $C # .
1 2 3
eval .
$ A=1 B=2 C=3
$ A=4 B=5 C=6 eval 'echo $A $B $C'
4 5 6
$ echo $A $B $C #
1 2 3
array .
#!/bin/bash
r_num=1
set -f
while read -r record; do
IFS=: eval 'fields=($record)'
IFS=@ eval 'echo ">>> ${fields[*]}"'
echo record $r_num has ${#fields[@]} fields
let r_num++
done < <( cat datafile )
set +f
Tips
368
Recommand Sites
http://wiki.bash-hackers.org
This wiki is intended to hold documentation of any kind about the GNU Bash. The main
motivation was to provide human-readable documentation and information to not force
users to read every bit of the Bash manpage - which is hard sometimes. However, these
docs here are not meant as newbie tutorial.
http://www.gnu.org/software/bash/manual
Bourne-Again SHell manual
http://mywiki.wooledge.org/BashGuide
Bash Guide
http://www.tldp.org/LDP/abs/html
Advanced Bash-Scripting Guide
http://www.tldp.org/LDP/Bash-Beginners-Guide/html
Bash Guide for Beginners
https://wiki.kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/index.html
Bash
https://wiki.kldp.org/HOWTO/html/Bash-Prog-Intro-HOWTO/
BASH
http://www.catonmat.net/sitemap
http://www.shellcheck.net
automatically detects problems with sh/bash scripts and commands.
http://explainshell.com
write down a command-line to see the help text that matches each argument
https://regex101.com/
Test regular expression
Recommand Sites
369