Вы находитесь на странице: 1из 369

Bash

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

Interactive vs Non-Interactive Shell

2.7

Login vs Non-Login Shell

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

Bash Shell Script

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

Session and Process Group

12.1

Process State Codes

12.2

TTY

12.3

Mutual Exclusion

12.4

Signals and Traps

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

Colors and Prompt

22

Tips

23
3

Bash Shell Script

Recommand Sites

24

Bash Shell Script

Introduction

Unix shell interactive


interpreter . script command history, alias, tab
completion, extended scripting syntax .
shell . script
. script if, else for, while
script shell .
shell script . shell
script , ,
. shell
.
Shell OS
. (
, ) Bug Reports
. , , .
Ubuntu 15.04 Bash version 4.3 .
.
.
( Night . )

Introduction

Bash Shell Script

Bug Reports, Comments

Bug Reports

Bash Shell Script

Shell script basics


Shell script .
globbing quote .

.
NUL , / .
.
[ , [10 , [[AA , {echo , {AA=10}

shell .
.
command arg1 arg2 arg3 ...

'' '' '' ...


.
? .
# 'commandarg1' .
commandarg1 arg2 arg3 ...
# 'arg1arg2' .
command arg1arg2 arg3 ...

shell script . if
[ shell builtin test
. ] .

Basics

Bash Shell Script

# [ 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

Bash Shell Script

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

Bash Shell Script

$ myfunc() { expr $1 + $2 ; return 5 ;}


$ AA=$(myfunc 1 2)
$ echo $? # $?
5
$ echo $AA # expr .
3


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

Bash Shell Script

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

Bash Shell Script

$ 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

Filename Expansion (Globbing)


Shell glob .
quote glob globbing
. Expansions and Substitutions -> Filename Expansion

$ AA="User-Agent: *" # AA glob '*'
$ echo "$AA" # quote globbing
User-Agent: *
$ echo $AA # quote globbing
User-Agent: 2013-03-19 154412.csv Address.java address.ser
ReadObject.class ReadObject.java robots.txt .txt
WriteObject.class WriteObject.java

Basics

12

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

-------- test.sh -------#!/bin/bash


echo arg1 : "$1"
echo arg2 : "$2"
------------------------$ ./test.sh 111 "111" # quote
arg1 : 111
arg2 : 111
$ ./test.sh hello world # .
arg1 : hello
arg2 : world
$ ./test.sh "hello world" # quote
arg1 : hello world
arg2 :
-----------------------$ AA="hello world"
$ ./test.sh $AA # .
arg1 : hello
arg2 : world
$ ./test.sh "$AA" # quote
arg1 : hello world
arg2 :

, ,

(backtick)

history ( )

Quotes

16

Bash Shell Script

$ 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

Bash Shell Script

.
. 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

Bash Shell Script

\ escape

# no quotes escape 'tr : n' .


$ echo 111:222:333 | tr : \n
111n222n333
$ echo 111:222:333 | tr : \\n
111
222
333

" , ' quote escape

$ echo double quotes \" , single quotes \'


double quotes " , single quotes '

\ \newline newline escape


. ( \ )
$ echo "I like \
> winter and \
> snow"
I like winter and snow # newline escape .

Double Quotes ( " " )


Double quotes $ ` !
. quote
.

Quotes

19

Bash Shell Script

$ 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

Double quotes escape

$ AA=hello
$ echo "$AA world `date +%Y`"
hello world 2015
# escape
$ echo "\$AA world \`date +%Y\`"
$AA world `date +%Y`

! history enable ! escape

history \ .
escape .
# history '\' .
$ echo "hello\!516world"
hello\!516world
$ echo "hello"\!"516world"
hello!516world
$ echo "hello"'!'"516world"
hello!516world

Quotes

20

Bash Shell Script

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 ( ' ' )


. escape .
single quotes $' ' .
$ AA=hello
$ echo '$AA world
> `date`
> \$AA
> '
$AA world
`date`
\$AA

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

Bash Shell Script

$' '
' ' 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

single quotes double quotes .


#
sed -rn '1p;2,${s/foo/bar/;p}'
# single quotes shell double quotes .
sed -rn '1p;2,${s/'"$var1/$var2"'/;p}'


quote .
$ ./args.sh 11 "hello "$'$world \u2665' 33
$0 : ./args.sh
$1 : 11
$2 : hello $world
$3 : 33

Quotes

22

Bash Shell Script

Escape Sequences
escape .
.
echo -e " " or ' '
$' '

printf " " or ' '


printf %b
Escape
Sequence

Character represented

\\

backslash

\a

alert (bell)

\b

backspace

\e

escape (ASCII 033)

\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

Ctrl-x , $'\cZ' Ctrl-Z (^Z)

$' '

Escape Sequences

printf

printf
printf

23

Bash Shell Script

* .

Escape Sequences

24

Bash Shell Script

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

Bash Shell Script

1 unset 2 null . unset 1


0 .
$ [ -v asdfghjk ]; echo $? # asdfghjk
1
$ asdfghjk=""
$ [ -v asdfghjk ]; echo $?
0
$ asdfghjk=123
$ [ -v asdfghjk ]; echo $?
0
$ unset asdfghjk
$ [ -v asdfghjk ]; echo $?
1

-u | set -o nounset script

Variables

26

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

#!/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

Bash Shell Script

#!/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

Bash Shell Script

#!/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

Bash Shell Script

--------- script.sh ------#!/bin/bash


echo hello
exit 4
---------- func1() -------func1() {
echo world
return 5
}
--------- -------$ ./script.sh
hello
$ echo $?
4
$ func1
world
$ echo $?
5

return .
.
. .
$ AA=$(expr 1 + 2)
$ echo $AA
3
$ AA=`date +%Y`
$ echo $AA
2015

Functions

33

Bash Shell Script

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

Bash Shell Script

$@ , $* . quote

quote "$@" "$1" "$2" "$3" ...


"$*" "$1c$2c$3 ... " . ( c IFS
. )
#!/bin/bash
foo() {
echo \$@ : $@
echo \$* : $*
echo '======== "$@" ======='
for v in "$@"; do
echo "$v"
done
echo '======== "$*" ======='
for v in "$*"; do
echo "$v"
done
}
foo 11 "22 33" 44
############# output #############
$@ : 11 22 33 44
$* : 11 22 33 44
======== "$@" =======
11
22 33
44
======== "$*" =======
11 22 33 44

indirection array

Functions

35

Bash Shell Script

#!/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

Bash version 4.3+ named reference .


declare -n refname
local -n refname
#!/bin/bash
f2() {
declare -n RVAR=$1 # declare local
RVAR=200
}
f1() {
local VAR=100
echo f1 : local VAR = $VAR
f2 VAR
echo f1 : local VAR after f2 call = $VAR
}
f1
###################### output #########################
f1 : local VAR = 100
f1 : local VAR after f2 call = 200

Functions

36

Bash Shell Script

named reference array .


indirection array .
foo() {
echo "$1"
local -n ARR=$2
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

37

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

# .
$ 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

Bash Shell Script

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:]]

POSIX character class . ( alnum, alpha, ascii, blank, cntrl,


digit, graph, lower, print, punct, space, upper, word, xdigit )

[^ ... ] or
[! ... ]

^ , ! Not . [^XYZ] XYZ


.
sh ! .

Pattern Matching

41

Bash Shell Script

$ 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

Bash Shell Script

# *.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

Bash Shell Script

#!
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

Bash Shell Script

#!/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

Bash Shell Script

Interactive vs Non-Interactive Shell


Shell .
interactive shell script noninterative shell . history alias, job control interactive
shell script disable .
Interactive shell .
# '$-' set option flags
# 'i' interactive .
case $- in
*i*) echo interactive shell ;;
*) echo non-interactive shell ;;
esac

Script alias disable .


alias script alias
. ( alias . )

Script history disable .


history interactive shell script
disable . history builtin .

Script job control disable .


job control interactive shell script disable .
& background job bg, fg,
suspend . jobs, wait, disown .

Script exec .
exec
script .

Interactive vs Non-Interactive Shell

46

Bash Shell Script

Interactive shell ~/.bashrc shell script bash -c


Non-Interactive shell BASH_ENV .

Interactive vs Non-Interactive Shell

47

Bash Shell Script

Login vs Non-Login Shell


shell .
ssh telnet login login shell
non-login shell .
login shell shopt -q login_shell; echo $? .

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 .

Login shell logout builtin .

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
.

Real user id vs Effective user id


Real user id id $UID readonly .
effective user id set uid $EUID readonly
. .

Login vs Non-Login Shell

48

Bash Shell Script

### alice ###


alice@box:/tmp/priv$ cp /bin/bash bash
alice@box:/tmp/priv$ chmod u+s bash # set uid
### bob ###
bob@box:/tmp/priv$ ./bash -p
bash-4.3$ id # euid alice
uid=1002(bob) gid=1005(gamers) euid=1004(alice) groups=1002(bob),1005(gamers)

.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

Login vs Non-Login Shell

49

Bash Shell Script

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

Bash Shell Script

@ , *
Double quotes ${array[@]} ${array[*]} .
IFS . " " quote @ *
. "array[@]" array " " quote
"array[*]" array " " IFS
.
Quote

${AA[@]}
${AA[*]}

quote

"${AA[@]}"

"${AA[0]}" "${AA[1]}" "${AA[2]}" ...

"${AA[*]}"

"${AA[0]}X${AA[1]}X${AA[2]}..."
'X' IFS

Arrays

51

Bash Shell Script

# 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

Bash Shell Script

$ 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]}

indexed array N ( stringlength )


associative array index string

${array[@]}
${array[*]}

array value

${!array[@]}
${!array[*]}

array index

${!name@}
${!name*}

name
) echo "${!BASH@}"

Array
index [ ] (( ))
.

Arrays

53

Bash Shell Script

########## indexed array #########


AA=( 11 "hello array" 22 )
AA=( [0]=11 [1]="hello array" [2]=22 )
AA[0]=11
AA[1]="hello array"
AA[2]=22
######## associative array #######
declare -A AA # declare -A
AA=( [ab]=11 [cd]="hello array" [ef]=22 )
AA[ab]=11
AA[cd]="hello array"
AA[ef]=22

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

Bash Shell Script

$ 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]"

associative array index string

array ${#array[@]} for


. index index
. array index .

Arrays

55

Bash Shell Script

$ 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

null : unset null


. .
$ AA=":arch linux:::ubuntu linux::::fedora linux::"
$ IFS=: read -ra ARR <<< "$AA"
$ echo ${#ARR[@]}
10
$ echo ${ARR[0]}
$ echo ${ARR[1]}
arch linux
# ARR null
$ set -f; IFS='' # IFS null
$ ARR=( ${ARR[@]} ) # quotes .
$ set +f; IFS=$' \n\t'
$ echo ${#ARR[@]}
3
$ echo ${ARR[0]}
arch linux
$ echo ${ARR[1]}
ubuntu linux

Array

Arrays

56

Bash Shell Script

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

Bash Shell Script

$ AA=( "Arch Linux" "Ubuntu Linux" "Suse Linux" "Fedora Linux" )


# 'u' 'X' .
# Ubuntu Linux Suse Linux .
$ echo "${AA[@]/u/X}"
Arch LinXx UbXntu Linux SXse Linux Fedora LinXx
# '//pattern' .
$ echo "${AA[@]//u/X}"
Arch LinXx UbXntX LinXx SXse LinXx Fedora LinXx
# Su* .
# .
$ echo "${AA[@]/Su*/}"
Arch Linux Ubuntu Linux Fedora Linux
$ AA=( "${AA[@]/Su*/}" )
$ echo ${#AA[@]} # 4 .
4
$ for v in "${AA[@]}"; do echo "$v"; done
Arch Linux
Ubuntu Linux
# index 2 .
Fedora Linux


$ 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

Bash Shell Script

$ AA="Arch Linux:Ubuntu Linux:Suse Linux:Fedora Linux"


$ IFS=: read -ra ARR <<< "$AA"
$ echo ${#ARR[@]}
4
$ echo "${ARR[1]}"
Ubuntu Linux
--------------------------------------------------------------------# glob globbing
# noglob
$ set -f; IFS=: # IFS ':'
$ ARR=( $AA )
$ set +f; IFS=$' \t\n' # array IFS
$ echo ${#ARR[@]}
4
$ echo "${ARR[1]}"
Ubuntu Linux
-------------------------------------------------------------------# array .
$ set -f; IFS=: # globbing disable
$ set -- $AA # IFS
$ set +f; IFS=$' \t\n' # positional parameters
$ echo $#
4
$ echo "$2"
Ubuntu Linux

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

Bash Shell Script

Array index .
[ ] .
$ AA=(1 2 3 4 5)
$ idx=2
$ echo "${AA[idx == 3 ? 1 : 2]}"
3

Arrays

60

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

########## ##########
$ [ ]; 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

Bash Shell Script

[ quote .

$AA quote [ -n $AA ]


[ -n ] . -n "-n" true
. quote [ -n "" ]
.
$ AA="" # AA null
$ [ -n $AA ]; echo $? # null true true .
0
$ [ -n "$AA" ]; echo $? # quote .
1

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

Bash Shell Script

[ and, or -a , -o , && || shell

. [
, 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

Bash Shell Script

$ 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

Bash Shell Script

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

Bash Shell Script

-a <FILE>

true .
( Logical AND
. )

-e <FILE>

true .

-f <FILE>

regular true .

-d <FILE>

directory true .

-c <FILE>

character special true .


( character special )

-b <FILE>

block special true .

-p <FILE>

(named, unnamed) pipe true .

-S <FILE>

socket true .

-L <FILE>

symbolic link true .

-h <FILE>

symbolic link true .

-g <FILE>

sgid bit true .

-u <FILE>

suid bit true .

-k <FILE>

sticky bit true .

-r <FILE>

readable true .

-w <FILE>

writable true .

-x <FILE>

executable true .

-O <FILE>

uid (user id) true .

-G <FILE>

gid (group id) true .

-N <FILE>

read modify true


.

-s <FILE>

0 (not empty) true .

-t <fd>

FD true .

<FILE1> -nt
<FILE2>

FILE1 FILE2 newer true .

<FILE1> -ot
<FILE2>

FILE1 FILE2 older true .

<FILE1> -ef
<FILE2>

FILE1 FILE2 hardlink true .

String Tests

Operators

68

Bash Shell Script

< , > shell


.
shell .
shell <= , >= . =
< , > redirection .
< , > (lexicographically)

(100 2 ). shell redirection


escape .

-z <STRING>

null true .
( . )

-n <STRING>

null true .

<STRING1> = <STRING2>

true .

<STRING1> != <STRING2>

true .

<STRING1> < <STRING2>

1 true .
( escape . )

<STRING1> > <STRING2>

1 true .
( escape . )

Arithmetic Tests

<INTEGER1> -eq
<INTEGER2>

true .

<INTEGER1> -ne
<INTEGER2>

true .

<INTEGER1> -le <INTEGER2>

INT1 INT2 , true


.

<INTEGER1> -ge
<INTEGER2>

INT1 INT2 , true


.

<INTEGER1> -lt <INTEGER2>

INT1 INT2 true .

<INTEGER1> -gt <INTEGER2>

INT1 INT2 true .

Misc Syntax

Operators

69

Bash Shell Script

<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>

named reference true . (bash version 4.3+).

Operators

70

Bash Shell Script

Subshells
Shell .
process parent child process .
/bin/sleep bash shell process sleep child
process .

AA.sh shell script bash child


process sleep .

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

Child process parent process



export ,
file descriptor ( stdin(0), stdout(1), stderr(2) ... )

Subshells

71

Bash Shell Script

ignore ( trap '' INT )



$ echo "pid : $$, PPID : $PPID"
pid : 10875, PPID : 1499 # shell pid ppid
$ pwd # working
/home/mug896/tmp
$ var1=100 var2=200
$ export var1 # var1 export
$ f1() { echo "I am exported function" ;}
$ f2() { echo "I am not exported function" ;}
$ export -f f1 # f1 export
$ trap '' SIGINT # INT ignore
$ trap 'rm -f /tmp/tmpfile' SIGTERM
$ tty
/dev/pts/13
$ exec 3> /dev/null # FD 3

child process test.sh

Subshells

72

Bash Shell Script

---------- test.sh ----------


#!/bin/bash
echo "pid : $$, PPID : $PPID"
pwd
echo "var1 : $var1"
echo "var2 : $var2"
f1
f2
trap
ls -l /proc/$$/fd
----------------------------$ ./test.sh
pid : 11717, PPID : 10875 # ppid parent shell pid
/home/mug896/tmp
var1 : 100
var2 : # export
I am exported function
./test.sh: line 6: f2: command not found # export
trap -- '' SIGINT # ignore
total 0
lrwx------ 1 mug896 mug896 64 Aug 8 16:07 0 -> /dev/pts/13 # FD 0,1,2
lrwx------ 1 mug896 mug896 64 Aug 8 16:07 1 -> /dev/pts/13
lrwx------ 1 mug896 mug896 64 Aug 8 16:07 2 -> /dev/pts/13
l-wx------ 1 mug896 mug896 64 Aug 8 16:07 3 -> /dev/null # parent open FD

Subshell
export shell ,
trap handler ( trap 'rm -f tmpfile' INT )
pid $$
parent pid $PPID
subshell shell . subshell
shell .

Subshells

73

Bash Shell Script

$ ( echo "pid : $$, PPID : $PPID"


> pwd
> echo "var1 : $var1"
> echo "var2 : $var2"
> f1
> f2
> trap
> ls -l /proc/$BASHPID/fd )
pid : 10875, PPID : 1499 # pid, ppid shell
/home/mug896/tmp
var1 : 100
var2 : 200
I am exported function
I am not exported function
trap -- '' SIGINT
trap -- 'rm -f /tmp/tmpfile' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU
total 0
lrwx------ 1 mug896 mug896 64 08.08.2015 15:20 0 -> /dev/pts/13
lrwx------ 1 mug896 mug896 64 08.08.2015 15:20 1 -> /dev/pts/13
lrwx------ 1 mug896 mug896 64 08.08.2015 15:20 2 -> /dev/pts/13
l-wx------ 1 mug896 mug896 64 08.08.2015 15:20 3 -> /dev/null

Parent process child process


parent child parent
. child export child child parent
.
child shell parent
.
parent child .

Subshell
parent process export child process
. subshell export .
$ AA=100
$ ( echo AA value = "$AA" ) # AA export .
AA value = 100

Subshells

74

Bash Shell Script

shell subshell , .
shell .
$ AA=100
$ ( AA=200; echo AA value = "$AA" ) # subshell 200 .
AA value = 200
$ echo "$AA" # shell .
100

subshell shell subshell .

Subshells

75

Bash Shell Script

$ 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

Bash Shell Script

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

-E | set -o errtrace or -T | set -o functrace trace


subshell . child process trace .

$$ $BASHPID
$$ shell pid subshell .

subshell pid $BASHPID


.

$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

Bash Shell Script

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

"changed to 40", 40 "changed to 40", 30 .


change_index ( ) subshell parent index

.2
$ echo hello | read var; echo $var
$
$ echo hello | { read var; echo $var; }
$ hello

echo hello read var | subshell

echo $var . subshell echo $var


. { ;} group echo $var subshell
.

.3

Subshells

78

Bash Shell Script

#!/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

while nkeys $nkeys 0


. while | subshell parent nkeys
. .
#!/bin/bash
nKeys=0
while read -r line
do
#...do stuff
nKeys=$((nKeys + 1))
done < datafile
echo Finished writing $nKeys keys
########### output ###########
Finished writing 10 keys

shell child process, subshell


closure . subshell parent subshell
. subshell parent
subshell parent subshell
.

Subshells

79

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

1. ls
2. fork
fork unix . pid,
ppid (4). fork ,
PCB . bash shell
. $$ $PPID
export .
subshell . subshell $BASHPID pid
.

3. exec

Process Creation

82

Bash Shell Script


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

Bash Shell Script


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

Bash Shell Script

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/[

alias, function, builtin, . kill builtin


function function .
shell .
command : alias, function (builtin )
.

command .

builtin : alias, function builtin


.
enable : builtin disable .

alias , keyword escape


alias keyword .
disable .
alias, keyword \ .

Commands

85

Bash Shell Script

alias, keyword quote


time keyword /usr/bin/time
escape .
$ \time
$ 'time' # "time"

ls alias alias escape


.
$ \ls
$ 'ls' # "ls"

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

Bash Shell Script

. hello binary -n world hello


. [[ shell
$AA .

.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

Bash Shell Script

Aliases, Functions and Scripts


Shell alias function
script . .
alias, function shell ( shell, shell script )
shell script (: env
).
alias shell . function export child process
. script shell
.
vi alias export
.
alias, function shell process shell
. script child process
parent shell .
alias \ escape function command
.
shell alias script child process
function export -f shell
script .

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

Bash Shell Script

1. command --help
2. man command
3. info command
man page ( manual page ) unix .
.

User Commands

System Calls

C Library Functions

Devices and Special Files (usually found in /dev)

File formats and conventions e.g /etc/passwd, /etc/crontab

Games

Miscellaneous (including macro packages and conventions)

System Administration tools and Deamons (usually only for root)

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

Bash Shell Script

man page .
1990 GNU man page info . info
hyperlink markup language man page
.
$ info grep

Commands

90

Bash Shell Script

Bourne Shell Builtins


.
. filename [arguments]
filename shell . AA.sh . BB.sh
BB.sh . child process
AA.sh process .
function BB.sh return .
AA.sh .
filename / $PATH
non-zero .

:
:
. 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

Bash Shell Script

cd [-L|[-P [-e]] [-@]] [dir]


. -P

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

Bash Shell Script

AA.sh export BB.sh parent


process AA.sh .
export -f .

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

Bash Shell Script

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

Bash Shell Script

alias . alias non-interactive shell


.

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

Bash Shell Script

#!/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 .

if command -v python > /dev/null; then ...

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

Bash Shell Script

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

Bash Shell Script

-a

NAME indexed arrays .

-A

NAME associative arrays .

-i

NAME integer .
let .

-n

NAME named reference .

-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

Bash Shell Script

false
false
1 .
.
$ echo false
false
$ false
$ echo $?
1

fc
fc [-e ename] [-lnr] [first] [last]
command history
.
fc -s [pat=rep] [command]
! history .

$ printf "%s\n" "hello\tworld"


hello\tworld
$ fc -s %s=%b printf
printf "%b\n" "hello\tworld"
hello world

fg
fg [job_spec]
job control

help
help [-dms] [pattern ...]
Shell builtin .

history

Builtin Commands

99

Bash Shell Script

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

Bash Shell Script

array . array MAPFILE .


, array index
callback .
mapfile -t array < datafile # .
while read -r line
do
array[i]="$line"
i=$((i + 1))
done < datafile

-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

Bash Shell Script

$ 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

callback read array skip .


$ f1() { read -r line ;}
$ mapfile -t -C f1 -c 1 arr < datafile
# 200, 400 skip .
$ echo "${arr[0]}"
100 Emma Thomas
$ echo "${arr[1]}"
300 Madison Randy
$ echo "${arr[2]}"
500 Nisha Singh

popd
popd [-n] [+N | -N]
pushd, dirs directory stack stack
.

printf
printf [-v var] format [arguments]
Builtin Commands

102

Bash Shell Script

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

Bash Shell Script

$ shopt -s nullglob
$ shopt -q nullglob; echo $?
0
$ shopt -u nullglob
$ shopt -q nullglob; echo $?
1

source
source filename [arguments]
. (a period) .

bash filename $PATH


.

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

Bash Shell Script

typeset [-aAfFgilrtux] [-p] name[=value]


declare . (Obsolete)

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

Bash Shell Script

job control

Builtin Commands

106

Bash Shell Script

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

-d delim RS (record seperator) , IFS FS (field


seperator) . name REPLY
.
[name ...]
# name
$ read v1 <<< "1 2 3 4 5"
$ echo $v1
1 2 3 4 5
------------------------------# name name
$ read v1 v2 v3 <<< "1 2 3 4 5"
$ echo $v1
1
$ echo $v2
2
$ echo $v3
3 4 5
---------------------------------$ read _ v2 _ v4 _ <<< "1 2 3 4 5"
$ echo $v2
2
$ echo $v4
4

read IFS .

read

107

Bash Shell Script

$ IFS=':|@' read -r col1 col2 col3 col4 <<< "red:green|blue@white"


$ printf "col1: %s col2: %s col3: %s col4: %s\n" "$col1" "$col2" "$col3" "$col4"
col1: red col2: green col3: blue col4: white
--------------------------------------------------------------------------datetime="2008:07:04 00:34:45"
IFS=': ' read -r year month day hour minute second <<< "$datetime"

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

Bash Shell Script

# find -print0 -d null


# IFS null
find . -print0 | while IFS= read -rd '' file; do
echo "$file"
done
-----------------------------------------------# -d null .
$ read -rd '' whole < datafile
$ echo "$whole"
20081010 1123 xxx
20081011 1234 def
20081012 0933 xyz
...

-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

Bash Shell Script

$ 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

Bash Shell Script

exec 3< infile


while read -r -u 3 line; do
echo "$line"
done
exec 3>&-


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

Bash Shell Script

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

16 , 8 printf "%c" ... .


$ printf "hello \x41\x42\x43\n" # 16
hello ABC
$ printf "hello \101\102\103\n" # 8
hello ABC

-v var . (bash only)

$ printf -v IFS " \t\n"

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

Bash Shell Script

# %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

Bash Shell Script

$ printf "%d, %d\n" 10 -10 # signed decimal


10, -10
$ printf "%u, %u\n" 10 -10 # unsigned decimal
10, 18446744073709551606
$ printf "%o, %o\n" 10 -10 # unsigned octal
12, 1777777777777777777766
$ printf "%x, %x\n" 10 -10 # unsigned hexadecimal
a, fffffffffffffff6

%f : floating point number .


%e : scientific notation .
%E : %e E .
%g : floating point number scientific notation .
%G : %g scientific notation E .
%a : C99 hexadecimal floating point number . ( bash only )
%A : %a . ( bash only )

printf

114

Bash Shell Script

$ printf "%e\n" 123 # scientific notation


1.230000e+02
$ printf "%f\n" 123 # floating point number
123.000000
$ printf "%g\n" 123
123
$ printf "%f\n" 123.4567
123.456700
$ printf "%g\n" 123.4567 # floating point number
123.457
$ printf "%f\n" 12345678.123
12345678.123000
$ printf "%g\n" 12345678.123 # scientific notation
1.23457e+07
$ printf "%f\n" 0.0000123
0.000012
$ printf "%g\n" 0.0000123 # scientific notation
1.23e-05
$ printf "%a\n" 123.4567 # hexadecimal floating point number
0xf.6e9d495182a9931p+3

%s : escape .
%b : escape .

$ printf "%s\n" 'hello\tworld'


hello\tworld # escape
$ printf "%b\n" 'hello\tworld'
hello world # escape

%q : shell input escape .

printf

115

Bash Shell Script

# '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 .

$ printf "foo %%%s%%\n" bar


foo %bar%
$ printf "%c %c\n" abc def
a d
$ printf "today is %(%Y-%m-%d)T\n"
today is 2015-08-31

%n : . ( bash only )

printf

116

Bash Shell Script

$ printf "12345%n6789%n\n" num1 num2


123456789
$ echo $num1 $num2
5 9

Width
N : field width .
* : field width .

$ printf "%d %d %d\n" 100 200 300


100 200 300
$ printf "%10d %10d %10d\n" 100 200 300 # field width 10
100 200 300
$ printf "%*d %*d %*d\n" 10 100 15 200 20 300 # 10, 15, 20 *
100 200 300

Flags
- : field width left . ( default right . )

$ printf "%10d %10d %10d\n" 100 200 300


100 200 300
$ printf "%-10d %-10d %-10d\n" 100 200 300
100 200 300

0 : field width zero padding .

$ printf "%06d\n" 12 345 6789


000012
000345
006789

+ : + , - sign .

$ printf "%+10d %+10d %+10d\n" 100 -200 +300


+100 -200 +300

space : + sign space .

printf

117

Bash Shell Script

$ printf "%d\n" 100 -200 +300


100
-200
300
$ printf "% d\n" 100 -200 +300
100
-200
300

' : 1000 , . ( bash only )

$ printf "%'d\n" 123456789


123,456,789

# : alternative format .
%#o octal number 0 .

$ printf "%#o\n" 10
012

%#x , %#X hexadecimal number 0x , 0X .

$ printf "%#x %#X\n" 10 30


0xa 0X1E

%#g , %#G precision trailing zero .

$ printf "%g\n" 12.34


12.34
$ printf "%#g\n" 12.34
12.3400

Precision
. field width precision .

field width precision .


.N : precision .
.* : precision .

printf

118

Bash Shell Script

$ printf "%f\n" 123.987654321


123.987654
$ printf "%.3f\n" 123.987654321 # precision 3
123.988 #
$ printf "%.*f\n" 3 123.987654321 # '*' precision
123.988

%f %g precision .
%f %g .

$ printf "%.5f\n" 123.12345678 # 5


123.12346
$ printf "%.5g\n" 123.12345678 # 5
123.12
$ printf "%.5f\n" 0.0012345678
0.00123
$ printf "%.5g\n" 0.0012345678
0.0012346

%.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

Bash Shell Script

$ 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 "%*s\n" $(tput cols) "hello world"

printf

120

Bash Shell Script

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

Bash Shell Script

$ 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

Bash Shell Script

$ A=1 B=2 C=3


# 1. eval read quotes
# echo $A $B $C
# 2. : eval .
$ A=4 B=5 C=6 eval 'echo $A $B $C'
4 5 6
$ echo $A $B $C #
1 2 3


$ AA='find . -name'
$ BB='"*.sh"'
$ eval "$AA $BB"
args.sh
sub.sh
test.sh
...
...

eval eval echo


. echo eval
. eval .
$ eval "$(echo hello world | sed 's/hello/wc <<< /')"
1 1 6
$ echo $?
0
# 1. : eval echo .
$ echo "$(echo hello world | sed 's/hello/wc <<< /')"
wc <<< world # eval .
$ wc <<< world # 2.
1 1 6 # eval stdout
$ echo $?
0 # eval .


eval .

eval

123

Bash Shell Script

$ 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

Bash Shell Script

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

Bash Shell Script

#
$ 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

Bash Shell Script

-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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

Keyword Commands

130

Bash Shell Script

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

Bash Shell Script

A && {
B && {
echo "A and B both passed"
} || {
echo "A passed, B failed"
}
} || echo "A failed"

5 . { ... ;} , ( ... ) grouping


group . function .
group context .
6 . Shell keyword
. shell
keyword .

Compound Commands
compgen -k | column shell

. shell if else for, while .



. .

.
loop done .

if

if ... fi

case

case ... esac

select

select ... done

while

while ... done

until

until ... done

for

for ... done

redirection, |, & .
redirection, , & .

Compound Commands

132

Bash Shell Script

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

Bash Shell Script

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 .

if ! mount /mnt/backup &> /dev/null; then


echo "FATAL: backup mount failed" >&2
exit 1
fi
----------------------------------------if grep -q '2014-07-20' dbfile; then
...
fi

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 .

word, pattern globbing,


.
pattern glob quote escape .
case 0 , case

Compound Commands

134

Bash Shell Script

.
shopt -s nocasematch , .

read -p "Enter the name of an animal: " ANIMAL


echo -n "The $ANIMAL has "
case $ANIMAL in
horse | dog | cat)
echo -n 4
;;
man | kangaroo)
echo -n 2
;;
*)
echo -n "an unknown number of"
;;
esac
echo " legs."

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

Bash Shell Script

----------------- -----------------AA=( "horse" "dog" "cat" "man" "kangaroo" )


PS3="Enter number: "
----------------- test1.sh -----------------select ANIMAL in "${AA[@]}"
do
echo "You picked number $REPLY : $ANIMAL"
done
----------------- test2.sh -----------------AA+=( exit )
select ANIMAL in "${AA[@]}"
do
case $ANIMAL in
horse | dog | cat)
number_of_legs=4
;;
man | kangaroo)
number_of_legs=2
;;
exit)
exit
;;
*)
echo Not available
break
;;
esac
echo "You picked number $REPLY"
echo "The $ANIMAL has $number_of_legs legs."
done

Looping Constructs
while
while test-commands; do consequent-commands; done
while while , do , done .
.
.

Compound Commands

136

Bash Shell Script

while read read


. read -r line < infile infile close
. open
.
while read -r line < infile
do
echo "$line"
done
########## output ##########
Fred:apples:20:June:4
Fred:apples:20:June:4
Fred:apples:20:June:4
...
...

read while done .


done redirect while open
.
while read -r line
do
echo "$line"
done < infile

while |
cat infile | while read -r line
do
echo "$line"
done

Compound Commands

137

Bash Shell Script

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

Bash Shell Script

$ set -f; IFS=$'\n'


$ 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'

for (( expr1 ; expr2 ; expr3 )) ; do commands ; done


(( )) shell . for

.
$ for (( i = 0; i <= 5; i++ )) {
echo $i;
}
0
1
2
3
4
5

Compound Commands

139

Bash Shell Script

Special Expressions
Shell command arg1 arg2 ... shell
. shell
escape quote
. $(( )) , (( )) , let , [[ ]] [
.
sh $(( )) .

$(( ... )) , (( ... ))


.
.
. $ . $var,
var . quote (
quote ) 0
.
$ A=10
$ (( A = $A + A )) # A $ .
$ echo $A
20
$ A=(5 6 7)
$ (( A[0] = A[1] + ${#A[@]} )) # { } $ .
$ echo ${A[0]}
9

$(( )) (( )) subshell shell .

.
C . var++ , --var , a
? b : c , ( ) , , .

$(( )) (( )) .
, 0 . ( )

Special Expressions

140

Bash Shell Script

$ (( 1 < 2 )); echo $? # (( )) 0


0
$ (( 1 > 2 )); echo $? # (( )) 1
1
$ (( 0 )); echo $? # 0 1
1
$ (( 1 )); echo $? # 0 0
0
$ (( var = 0, res = (var ? 3 : 4) ))
$ echo $res
4
$ (( var = 1, res = (var ? 3 : 4) ))
$ echo $res
3
$ AA=10
$ while (( AA > 5 )); do
echo $AA
(( AA-- ))
done

for (( i = 0; i < 10; i++ )) !


(( )) ; . (( i = 0; i < 10;

i++ )) . for C for


.
for (( i = 0; i < 10; i++ ))
do
echo $i
done
############### or ################
for (( i = 0; i < 10; i++ )) {
echo $i
}

let

Special Expressions

141

Bash Shell Script

$(( )) (( ))

. 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 ( =~ )

. pattern regex quote


. pattern regex quote
.

Special Expressions

142

Bash Shell Script

##################### pattern matching #####################


[[ "hello world" = *llo\ wor* ]]; echo $? # pattern
0
$ [[ "hello world" = "*llo wor*" ]]; echo $? #
1
###################### regex matching ######################
$ [[ "hello world" =~ .*llo\ wor.* ]]; echo $? # regex
0
$ [[ "hello world" =~ ".*llo wor.*" ]]; echo $? #
1
# regex .
$ [[ "hello world" =~ "wor" ]]; echo $?
0

&& , || .
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 ( ) .

$BASH_REMATCH[0] ( ) $BASH_REMATCH[1] ... .

Special Expressions

143

Bash Shell Script

#!/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

Bash Shell Script

[[ ! $COLOR =~ BLUE|RED|GREEN ]] && {


echo "Incorrect options provided"
exit 1
}
-------------------------------------------------------------# .
raw_string='dumpvmcore [--filename=name] info [args...]
injec-tnmi log [[--release] | [--debug]] x [group-settings...]
logdest --release | debug-- [destinations...] log-flags
[[--release] | [--debug]] [flags...] osdetect os osdmesg
[--lines=lines] | pattern'
for word in $( echo -n "$raw_string" | tr -d '|' ); do
[[ $word =~ ^[[:alnum:]-]+{3,}$ ]] \
&& [[ ! $word =~ ^-|-$ ]] \
&& echo "$word"
done | sort -u

[ ] , [[ ]] quote
O : ( "$var" ) , X : ( $var )

unary

[ ]

[[ ]]

X , O
regex
quote

Special Expressions

145

Bash Shell Script

Shell Metacharacters
Shell script .
.
.
escape quote
.
C++ ,
Makefile cmake, qmake
make . shell
.
( ) ` && || & | ;
< > >> # redirection
* ? [ ] # glob
" ' # quote
\ $
= += #

( )
subshell
$( )
grouping

;
.

`
backtick $( ) .

&& ||

Shell Metacharacters

146

Bash Shell Script

AND, OR .
shell [[ ]] .
shell && || .

&
background .
; ;
.
command1 &; command2 & # error
command1 & command2 & # OK
{ ... command & ;} # error
{ ... command & } # OK

|
.
|& stdout, stderr 2>&1 | .

< > >>


redirection
>> (append) , >& , <> , &> ( >word 2>&1 ) , &>> ( >>word 2>&1 ) , >| (override

noclobber), << (here document) , <<- (no leading tab) , <<< (here string)

;
.
;; case pattern) .

* ? [ ]
glob .

Shell Metacharacters

147

Bash Shell Script

" '
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'

find shell ( ) , ; quote escape


.

Shell Metacharacters

148

Bash Shell Script

# '( )' shell


$ find . -type f ( -name "*.log" -or -name "*.bak" ) -exec rm -f {} ;
bash: syntax error near unexpected token '('
# '( )' quote ';'
$ find . -type f '(' -name "*.log" -or -name "*.bak" ')' -exec rm -f {} ;
find: missing argument to '-exec'
# shell escape .
$ find . -type f '(' -name "*.log" -or -name "*.bak" ')' -exec rm -f {} ';'
no error !
$ find . -type f \( -name "*.log" -or -name "*.bak" \) -exec rm -f {} \;
no error !

shell .
.
# '( )'
$ (true)&&(true;false); echo $?
$ 1
# '{ }'
$ (true)&&{true;false;}; echo $?
bash: syntax error near unexpected token `}'

{ } shell keyword
{ } , , , brace

Shell Metacharacters

149

Bash Shell Script

#
$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 {} \;

' ! ' shell keyword


! .

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 .

(non-interactive shell script history disable ).

Shell Metacharacters

150

Bash Shell Script

$ !comp # history
compgen -k | column
$ echo "hello!516world" # double quotes history !
hellocompgen -k | columnworld

$ echo 'hello!516world' # single quotes .


hello!516world
# double quotes history
$ echo "hello"\!"516world" # "hello"'!'"516world"
hello!516world
---------------------------------------------------------# '!=' history .
$ [ aaa != bbb ]; echo $?
0

+= .
+= array . ( sh

. )

Shell Metacharacters

151

Bash Shell Script

##### variable #####


$ AA=hello
$ AA+=" world"
$ echo "$AA"
hello world

##### indexed array #####


$ ARR=(11 22 33)
$ ARR+=(44)
$ echo ${ARR[@]}
11 22 33 44

##### associative array #####


$ ARR=([i1]=aaa [i2]=bbb [i3]=ccc)
$ ARR+=([i4]=ddd)
$ echo ${ARR[@]}
ccc bbb aaa ddd
$ echo ${!ARR[@]}
i3 i2 i1 i4

Shell ' , '


array .

Shell Metacharacters

152

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

$ { echo foobar > z1 ;} > z2


$ cat z1
foobar
$ cat z2

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

Bash Shell Script

Expansions and substitutions


enter shell tokens (words)
, ,
. quotes .
shell .
1 . Brace expansion
2 . Tilde expansion
3 . 4 left-to-right .
Parameter expansion
Arithmetic expansion
Command substitution
Process substitution
$ i=1
$ echo $i $((i++)) $i # left-to-right
1 1 2 # '1 1 1' '1 1 2' .

4 . Word splitting
5 . Pathname expansion (globbing)
globbing .
( )

Expansions and Substitutions

156

Bash Shell Script

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

Bash Shell Script

$ echo X{apple,banana,orange,melon} # X preamble


Xapple Xbanana Xorange Xmelon
$ echo {apple,banana,orange,melon}Y # Y postscript
appleY bananaY orangeY melonY
# preamble, postscript space .
$ echo {apple,banana,orange,melon}
apple banana orange melon
$ echo X{apple,banana,orange,melon}Y
XappleY XbananaY XorangeY XmelonY
# '/home/bash/test/' preamble
$ mkdir /home/bash/test/{foo,bar,baz,cat,dog}
$ ls /home/bash/test/
bar/ baz/ cat/ dog/ foo/
$ tar -czvf backup-`date +%m-%d-%Y-%H%M`.tar.gz \
--exclude={./public_html/cache,./public_html/compiled,./public_html/images} \
./public_html
# 'http://docs.example.com/slides_part' preamble '.html' postscript
$ curl --remote-name-all http://docs.example.com/slides_part{1,2,3,4}.html
$ ls
slides_part1.html slides_part2.html slides_part3.html slides_part4.html

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

Bash Shell Script

$ 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

Bash Shell Script

$ 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__

# 'http://docs.example.com/slides_part' preamble '.html' postscript


$ curl --remote-name-all http://docs.example.com/slides_part{1..4}.html
$ ls
slides_part1.html slides_part2.html slides_part3.html slides_part4.html

Combining and nesting


{ } combining .

$ 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

Bash Shell Script

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

Bash Shell Script

Tilde Expansion
~ . double quotes .

Home
~ . $HOME .
~USERID USERID .

$ echo ~ # .
/home/bashhacker
$ echo ~man # 'man' .
/var/cache/man


~+ $PWD .


~- $OLDPWD .

Tilde Expansion

162

Bash Shell Script

Parameter Expansion
(
parameter ) ( variable )

.
.
.

shell script
. sh substring expansion, search and replace, indirection, case
modification .


AA=cde AA 'cde' .
$ . AA

'abcdefg' echo "ab$AAfg" 'AA'


'AAfg' .
{ }
.
$ AA=cde
$ echo "ab$AAfg" # $AAfg null 'ac' .
ac
$ echo "ab${AA}fg" # '{ }' .
abcdefg

String length
${#PARAMETER}
# . array @ , *
.
$ AA="hello world"
$ echo ${#AA}
11

Parameter Expansion

163

Bash Shell Script

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

Bash Shell Script

$ 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

Search and replace

Parameter Expansion

165

Bash Shell Script

${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

Use a default value


${PARAMETER:-WORD}
${PARAMETER-WORD}

Parameter Expansion

166

Bash Shell Script

${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

Bash Shell Script

$ 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

Assign a default value


${PARAMETER:=WORD}
${PARAMETER=WORD}
Use a default value . .
AA .
AA=""
$ echo ${AA:-linux}
linux
$ echo $AA # ':-' AA .
$ echo ${AA:=linux}
linux
$ echo $AA # ':=' AA .
linux

Array[@] .

Parameter Expansion

168

Bash Shell Script

$ AA=()
$ echo ${AA[@]:=11 22 33}
bash: AA[@]: bad array subscript
11 22 33

Use an alternate value


${PARAMETER:+WORD}
${PARAMETER+WORD}
${AA:+linux} : AA linux .
null null .
${AA+linux} : AA ( null ) linux .
null .
$ AA=hello
$ echo ${AA:+linux} # AA linux .
linux
$ echo ${AA+linux}
linux
$ AA=""
$ echo ${AA:+linux} # ':+' null null .
$ echo ${AA+linux} # '+' null linux .
linux
$ unset AA
$ echo ${AA:+linux} # null .
$ echo ${AA+linux}
# FUNCNAME '()'
echo ${FUNCNAME:+${FUNCNAME}()}

Display error if null or unset


${PARAMETER:?[error message]}
${PARAMETER?[error message]}

Parameter Expansion

169

Bash Shell Script

${AA:?error message} : AA . AA null


error message script . $? 1
.
${AA?error message} : AA . AA error
message script . $? 1 .
error message 'parameter null or not set' .
$ AA=hello
$ echo ${AA:?null or not set} # AA AA
hello
$ echo ${AA?not set}
hello
$ AA=""
$ echo ${AA:?null or not set} # ':?' null
bash: AA: null or not set # error message $? 1
$ echo $?
1
$ echo ${AA?not set} # '?' null
# .
$ unset AA
$ echo ${AA:?null or not set} #
bash: AA: null or not set # error message .
$ echo $?
1
$ echo ${AA?not set}
bash: AA: not set
$ echo $?
1
$ echo ${AA?} # error message .
bash: AA: parameter null or not set

Case modification
${PARAMETER^}
${PARAMETER^^}
${PARAMETER,}
${PARAMETER,,}
${PARAMETER^} : .
${PARAMETER^^} : .
${PARAMETER,} : .

Parameter Expansion

170

Bash Shell Script

${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

Bash Shell Script

---------- args.sh -----------#!/bin/bash


for (( i = 0; i <= $#; i++ ))
do
echo \$$i : ${!i} # ${$i} .
done
------------------------------$ args.sh 11 22 33
$0 : ./args.sh
$1 : 11
$2 : 22
$3 : 33

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

Bash Shell Script

Arithmetic Expansion
$(( )) , (( )) bash . sh
$(( )) . expr, bc .

,
. shell escape
. Special Expressions
array index [ ] . $[ ]
deprecated .

Arithmetic Expansion

173

Bash Shell Script

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

Bash Shell Script

# 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

Bash Shell Script

$ 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

Bash Shell Script

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

sleep shell cat subshell


.
{ sleep 10 ;} > >( cat )

shell subshell FD
Process Substitution

177

Bash Shell Script

command1 > >( command2 ) command1 stdout command2 stdin

command1 < <( command2 ) command2 stdout command1


stdin .
shell pid $$ subshell >( )
FD $BASHPID .

>( . . . )
shell stdout subshell stdin
.

<( . . . )
subshell stdout shell stdin
.

Process Substitution

178

Bash Shell Script

)
. 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

Bash Shell Script

$ echo hello > >( wc )


1 1 6
$ wc < <( echo hello )
1 1 6
-----------------------#
$ f1() {
cat "$1" > "$2"
}
$ f1 <( echo 'hi there' ) >( tr a-z A-Z )
HI THERE
-----------------------------------------------------# --log-file
$ rsync -arv --log-file=>(grep -vF .tmp > log.txt) src/ host::dst/
----------------------------------------------------------------# tee 4
$ ps -ef | tee >(grep tom > toms-procs.txt) \
>(grep root > roots-procs.txt) \
>(grep -v httpd > not-apache-procs.txt) \
>(sed 1d | awk '{print $1}' > pids-only.txt)
----------------------------------------------------------------# dd
dd if=<( cat /dev/urandom | tr -dc A-Z ) of=outfile bs=4096 count=1

|
subshell parent
. shell .

Process Substitution

180

Bash Shell Script

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

Bash Shell Script

#!/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

Bash Shell Script

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 IFS space, tab, newline .


space tab, newline . IFS

space . space
.
Internal Field Separator ( IFS )
. read
, array . space, tab,
newline IFS unset . IFS null
.
$ echo -n "$IFS" | od -a
0000000 sp ht nl

IFS .

Word Splitting

183

Bash Shell Script

$ 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

Bash Shell Script

$ ls
2013-03-19 154412.csv ReadObject.java WriteObject.class
ReadObject.class .txt WriteObject.java

$ for file in $(find .)


do
echo "$file"
done
.
./WriteObject.java
./WriteObject.class
./ReadObject.java
./2013-03-19 # 2
154412.csv
./ReadObject.class
./ # 3

.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

Bash Shell Script

Filename Expansion ( Globbing )


* . ls *.sh
.sh . * glob
glob globbing .
glob * ? [ ] shell pattern matching
. globbing
glob . quote ,
globbing .
$ ls
address.c address.h readObject.c readObject.h WriteObject.class
Address.class Address.java ReadObject.class ReadObject.java WriteObject.java
$ ls *.[ch]
address.c address.h readObject.c readObject.h
$ ls "*.[ch]" # quote globbing
ls: cannot access *.[ch]: No such file or directory
$ echo *.?
address.c address.h readObject.c readObject.h
$ for file in *.[ch]; do echo "$file"; done
address.c
address.h
readObject.c
readObject.h

shell select globbing .


, globbing .

Filename Expansion

186

Bash Shell Script

for file in $(find . -type f) ... # Wrong!


for file in `find . -type f` ... # Wrong!
arr=( $(find . -type f) ) ... # Wrong!
------------------------------------------# , globbing .
# newline .
set -f; IFS=$'\n'
for file in $(find . -type f) ...
set +f; IFS=$' \t\n'
set -f; IFS=$'\n'
arr=( $(find . -type f) ) ...
set +f; IFS=$' \t\n'
------------------------------------------------------------------# find -print0 -d null
# IFS null
find . -type f -print0 | while IFS='' read -r -d '' file; do
echo "$file"
done
#
while IFS= read -rd '' file; do
echo "$file"
done < <( find . -type f -print0 )

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

Bash Shell Script

set -o noglob globbing disable . globbing

. globbing globbing disable


glob .

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

Bash Shell Script

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

Bash Shell Script

.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

Bash Shell Script

$ array=( [10]=100 [11]=200 [12]=300 )


$ echo ${array[12]}
300
$ touch array1 # array1
# unset globbing array[12] array1
#
$ unset -v array[12]
$ echo ${array[12]}
300
$ unset -v "array[12]" # globbing disable quote.
$ echo ${array[12]} # unset

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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

$ wc < infile > outfile


$ cat outfile
2 2 12

Redirection
< , > . .

$ wc 0 < infile 1> outfile # 0 wc .


wc: 0: No such file or directory
$ wc 0< infile 1 > outfile # 1 wc .
wc: 1: No such file or directory

> 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

Bash Shell Script

$ mycomm 2>&1 > outfile #


$ mycomm > outfile 2>&1 #

exec . exec shell


redirection shell
. ls -l /proc/$$/fd FD 0, 1, 2
/dev/pts/10 () .
# '$$' shell process id .
$ ls -l /proc/$$/fd
total 0
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

exec
. shell process id exec echo $$
.

mycomm 2>&1 > outfile


$ exec 2>&1
FD 2 FD 1 . 1, 2
. stderr stdout .
$ ls -l /proc/20040/fd
total 0
lrwx------ 1 mug896 mug896 64 07.06.2015 15:56 0 -> /dev/pts/10 # stdin
lrwx------ 1 mug896 mug896 64 07.06.2015 15:56 1 -> /dev/pts/10 # stdout
lrwx------ 1 mug896 mug896 64 07.06.2015 15:56 2 -> /dev/pts/10 # stdout

$ exec 1> outfile


FD 1 outfile 1 . redirection FD 1
outfile . FD 1 outfile FD
2 stdout .
$ ls -l /proc/20040/fd
total 0
lrwx------ 1 mug896 mug896 64 07.06.2015 15:56 0 -> /dev/pts/10 # stdin
l-wx------ 1 mug896 mug896 64 07.06.2015 15:56 1 -> /home/mug896/outfile
lrwx------ 1 mug896 mug896 64 07.06.2015 15:56 2 -> /dev/pts/10 # stdout

Redirections

195

Bash Shell Script

stdout errmessage
.
# { ;} outfile errmessage .
{ mycomm 2>&1 > outfile ;} > errmessage

mycomm > outfile 2>&1


$ exec 1> outfile
FD 1 outfile 1 .
$ ls -l /proc/19779/fd
total 0
lrwx------ 1 mug896 mug896 64 07.06.2015 15:33 0 -> /dev/pts/11
l-wx------ 1 mug896 mug896 64 07.06.2015 15:33 1 -> /home/mug896/tmp/outfile
lrwx------ 1 mug896 mug896 64 07.06.2015 15:33 2 -> /dev/pts/11

$ 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

Bash Shell Script

# 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----------------

stdin, stdout redirect .

Redirections

197

Bash Shell Script

#!/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

exec 0<&3- 1>&4- # FD 0, 1


# outfile
# .
echo end -----------------

Subshell redirection while .

Redirections

198

Bash Shell Script

#!/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

Bash Shell Script

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

Bash Shell Script

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 -f x; sed -e 's/0/X/g' > x ;} < x x


< x open
. x x inode .
$ stat -c %i x; { rm -f x; sed -e 's/0/X/g' > x ;} < x; stat -c %i x
1709909
1709910

rm
.

Redirections

201

Bash Shell Script

$ { rm -f x; sed -e 's/0/X/g' < x ;} > x


bash: x: No such file or directory

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

Bash Shell Script

# 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

Bash Shell Script

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

Bash Shell Script

# : 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

Bash Shell Script

$ exec 4< infile


# read `lr-x------` .
$ ls -l /proc/$$/fd/4
lr-x------ 1 mug896 mug896 64 04.07.2015 10:56 /proc/9363/fd/4 -> /home/mug896/tmp/infile

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

Bash Shell Script

$ exec 5<> iofile


# read, write `lrwx------` .
$ ls -l /proc/$$/fd/4
lrwx------ 1 mug896 mug896 64 04.07.2015 10:56 /proc/9363/fd/5 -> /home/mug896/tmp/iofile
$ cat <&5
hello world
$ echo this is a test >&5
$ cat iofile
hello world
this is a test
$ exec 5>&-

<> .

overwrite .
.

File Descriptors

207

Bash Shell Script

$ 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

Bash Shell Script

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 # ( )
$

Named file descriptor


FD FD
. { }
.

File Descriptors

209

Bash Shell Script

$ exec {myFD}> outfile


$ echo $myFD
10
$ ls -l /proc/$$/fd/$myFD
l-wx------ 1 mug896 mug896 64 04.07.2015 10:56 /proc/9363/fd/10 -> /home/mug896/tmp/outfile
# $myFD, ${myFD} .
$ exec {myFD}>&$ ls -l /proc/$$/fd/$myFD
ls: cannot access /proc/9363/fd/10: No such file or directory
$ ( echo 111 >& $fd1 ) {fd1}> >( cat )
111

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

Bash Shell Script

<<< , <<
Here string ( <<< ) , here document ( << ) .
echo cat . bash -c here docuemnt
stdin sh-thd-4029673544
.
sh here document .

$ bash -c 'ls -l /proc/$$/fd' <<EOF # here document


hello
EOF
total 0
lr-x------ 1 mug896 mug896 64 Jul 5 00:08 0 -> /tmp/sh-thd-4029673544 (deleted)
lrwx------ 1 mug896 mug896 64 Jul 5 00:08 1 -> /dev/pts/11
lrwx------ 1 mug896 mug896 64 Jul 5 00:08 2 -> /dev/pts/11
-------------------------------------------------------------$ bash -c 'ls -l /proc/$$/fd' <<< "hello" # here string
total 0
lr-x------ 1 mug896 mug896 64 Jul 5 00:20 0 -> /tmp/sh-thd-4029677356 (deleted)
lrwx------ 1 mug896 mug896 64 Jul 5 00:20 1 -> /dev/pts/11
lrwx------ 1 mug896 mug896 64 Jul 5 00:20 2 -> /dev/pts/11

<<< (here string)


subshell
. here string shell
.
# read '|' subshell
$ echo "here string test" | read var
$ echo $var

# '<<<' shell .
$ read var <<< "here string test"
$ echo $var
here string test

<<< , <<

211

Bash Shell Script

<< (here document)


Here string .
.
escape double quotes " escape
. single, double quotes escape echo
. quotes , .
# single, double quotes escape .
$ cat <<EOF
> this is "double quotes"
> this is 'single quotes'
> EOF
this is "double quotes"
this is 'single quotes'
# , .
$ AA=100
$ cat <<ABC # ABC
> here $AA
> document $(date +%D)
> ABC
here 100
document 07/23/15
# quotes , .
$ AA=100
$ cat <<'END' # END
> here $AA
> document $(date +%D)
> END
here $AA
document $(date +%D)

Here document
$ cat <<END > outfile
> here
> document
> END

Here document

<<< , <<

212

Bash Shell Script

$ cat <<END | tr a-z A-Z


here
document
END
HERE
DOCUMENT

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

Bash Shell Script

$ 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

Bash Shell Script

Pipe
. .
: inventory.db 3
c
.
.
cat inventory.db | cut -d ':' -f 3 | grep '^c' | sort

,
. . "

" .

stdin, stdout, stderr


(stdin), (stdout) ,
(stderr) program1 program2
program2 program3 program3
. .

subshell .
Pipe

215

Bash Shell Script

{ echo; sleep 10 ;} | { echo; sleep 10 ;} | { echo; sleep 10 ;}


subshell
.
.

shopt -s lastpipe shell .

job control disable non-interactive shell script


disable .

shell FD
shell FD (File Descriptor) . shell pid
$$ subshell subshell FD
$BASHPID . $$ shell FD

. stdout
, stdin, stdout .
stdin .

Pipe

216

Bash Shell Script


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

Bash Shell Script

?
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

Bash Shell Script


.
# 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

Bash Shell Script

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;

pipe random access .


open .
named pipe . nc localhost
8080 request stdout
. nc www.naver.com 80 . |
request naver . naver nc
stdout > mypipe . naver
> mypipe nc < mypipe

.
$ mkfifo mypipe
$ nc -l localhost 8080 < mypipe | nc www.naver.com 80 > mypipe

named pipe | .

Pipe FIFO

Named Pipe

220

Bash Shell Script

Pipe FIFO ( First In First Out ) . pipe


pipe .
$ mkfifo mypipe
# FD block .
$ exec 3<> mypipe
$ echo 111 > mypipe
$ echo 222 > mypipe
$ echo 333 > mypipe
$ read var < mypipe; echo $var
111
$ read var < mypipe; echo $var
222
$ read var < mypipe; echo $var
333
$ exec 3>&-

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

Bash Shell Script

# writer , reader block .


$ while :; do echo $(( i++ )); sleep 1; done > mypipe &
[1] 17103
$ cat mypipe # reader
0
1
2
3
4
^C # ctrl-c
$ # Broken pipe writer
[1]+ Broken pipe while :; do
echo $(( i++ )); sleep 1;
done > mypipe

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

Bash Shell Script

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

Bash Shell Script

# 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
...

Pipe buffer size


Reader writer pipe buffer size
. ulimit -a pipe size 8 * 512 bytes = 4096
16 4096 * 16 = 65,536
. 4096 write
atomic .
/usr/src/linux-headers-3.19.0-25/include/linux/pipe_fs_i.h
#define PIPE_DEF_BUFFERS 16

Named Pipe

224

Bash Shell Script

$ 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

Multiple writers and readers


Pipe multiple writers, readers . ,
. multiple writers, single reader .
$ while :; do echo $(( i++ )); sleep 1; done > mypipe &
[1] 23084
$ while :; do echo --- $(( i++ )); sleep 1; done > mypipe &
[2] 23097
$ cat mypipe
0
1
2
--- 0
3
--- 1
4
--- 2
5
--- 3
6
--- 4
7
--- 5
...

Named Pipe

225

Bash Shell Script

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

Bash Shell Script

$ nc -U mysocket
hello
socket

FD

unix domain socket xwindows


/tmp/.X11-unix/ socket . lsof -U

unix domain socket . ( pipe


lsof | awk '$5 == "FIFO"' . )
unix domain socket socket
. internet domain socket
.
, packet protocol .
nc internet domain socket .

computer1 ifconfig ip nc -l 12.34.56.78 8080


. computer2 computer1 ip
nc 12.34.56.78 8080
.
computer1
$ nc -l 12.34.56.78 8080
hello
internet socket

computer2

Named Pipe

227

Bash Shell Script

$ 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

Bash Shell Script

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

Bash Shell Script

line buffered : newline .


full buffered : .
unbuffered : .
stdin, stdout, stderr stream
. ( open stream full buffered . )
stdin : line buffered or unbuffered full buffered
.
stdout : line buffered full buffered .
stderr : unbuffered . stderr .
tail -f unbuffered grep
full buffered awk
line buffered . grep
.



, . 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

Bash Shell Script

$ tail -f access.log | cut -d ' ' -f1 | tr A-Z a-z | uniq

gnu coreutils stdbuf .


$ tail -f access.log | stdbuf -oL cut -d ' ' -f1 | stdbuf -oL tr A-Z a-z | uniq

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

Bash Shell Script

$ coproc sed --unbuffered 's/^/foo/'


[1] 5993
$ echo bar >& ${COPROC[1]}
$ read -r res <& ${COPROC[0]}
$ echo $res
foobar

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

Bash Shell Script

stdin, stdout default size = 1024, 4096

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

Bash Shell Script

file descriptor low-level I/O high-level I/O


stream file descriptor FILE *
.
f* (fopen, fread, fwrite, fclose ...), printf, scanf stream
low-level I/O large chunks
nonblocking (or polled) control
.

Buffering

234

Bash Shell Script

Job Control
&
background job .
job background vi .
background process main process Ctrlc background .
.

job id job specification


$ curl -sO http://cdimage.ubuntu.com/.../ubuntu-mate-15.10-desktop-amd64.iso &
[3] 26558

& background job id process id


. [3] job id 26558 process id (pid) .
kill job job id pid
( ). job id job specification ( jobspec )
jobspec job id % . ( : %3 )
jobspec job control ( jobs, bg, fg, wait, disown, kill ) .
jobspec kill pgid ( process group id )
child process .

jobspec pid
pid jobspec .

Job Control

235

Bash Shell Script

$ sleep 10 | sleep 10 | sleep 10 &


[1] 12782
# jobspec 3 .
$ jobs
[1]+ Running sleep 10 | sleep 10 | sleep 10 &
# pid .
$ ps af
PID TTY STAT TIME COMMAND
...
1643 pts/10 Ss 0:00 bash
12780 pts/10 S 0:00 \_ sleep 10 # pid
12781 pts/10 S 0:00 \_ sleep 10 # pid
12782 pts/10 S 0:00 \_ sleep 10 # pid
...

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

Bash Shell Script

-p job table process id .


| process id .

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

Bash Shell Script

$! 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

Bash Shell Script

#!/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 .

Input and Output


Input
foreground job . background job
SIGTTIN suspend .

Job Control

239

Bash Shell Script

Output
session job .
background job redirection
.
stty tostop background job suspend

Shell background job ?


exit logout
background job . stopped running . shell exit
stopped job .
stopped job exit shell stopped
job .
running job shell background
. , parent process id (ppid) . background job
shell ppid shell . shell
ppid 1 init process ( or upstart ) . script
.
login shell shopt -s huponexit logout running
background job HUP .

remote login , , interactive shell kill -HUP
shell stopped, running job HUP
.
Ctrl-c
background job ctrl-c exit
shell ppid .

Controlling Terminal
TTY .

Double fork

Job Control

240

Bash Shell Script

A.sh B.sh background B.sh orphaned


process ppid init ( or upstart ) . init child process
wait system call
daemon .
background B.sh stdin /dev/null job table
.


{ ;} ( ) & background

subshell . { ;} shell background


subshell .
$ AA=100; echo $$;
18606
$ { AA=200; echo $$ ;} &
18606
$ echo $AA
100

Script job control disable .


non-interactive shell script job control disable .
& background process bg, fg,
suspend . jobs, wait, disown .
set -o monitor enable .

Job Control

241

Bash Shell Script

Session Process group


process id (pid) parent process id (ppid)
. session process group .
shell shell pid session id (sid) session leader
. process sid
.
shell script process group script pid process group id
(pgid) process group leader . script process
pgid . AA.sh script . bash
shell pid sid AA.sh pid pgid .

'|' process group


pgid process group leader . ( script
script pgid .) { echo; sleep 10 ;} | { echo;
sleep 10 ;} . bash shell pid sid

pid pgid .

process group job control ( job ) . session


process group foreground background .
( ) ,
.

Session and Process Group

242

Bash Shell Script


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 - .)

Session and Process Group

243

Bash Shell Script

$ 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

Session and Process Group

244

Bash Shell Script

Process State Codes


ps ax STAT .

uninterruptible sleep (usually IO)

running or runnable (on run queue)

interruptible sleep (waiting for an event to complete)

stopped, either by a job control signal or because it is being traced.

dead (should never be seen)

defunct ("zombie") process, terminated but not reaped by its parent.

BSD .

<

high-priority (not nice to other users)

low-priority (nice to other users)

has pages locked into memory (for real-time and custom IO)

is a session leader

is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

is in the foreground process group.

linux OS ps .

Process State Codes

245

Bash Shell Script

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 .

Process State Codes

246

Bash Shell Script

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
[ ] .

Process State Codes

247

Bash Shell Script

TTY
.
, ,
,
/dev /dev/tty* , /dev/pts/* ,
, , xterm gnometerminal emulation , telnet, ssh
.
, punch card , .
.
.
Operating System .

TTY

248

Bash Shell Script

Morse teletypewriter .

TTY

249

Bash Shell Script

Teletypewriter
. ,
. ,
command line interface . /dev tty
TeleTYpe .

TTY

250

Bash Shell Script

Teletype Corporation teletype model 33

2 teletypewriter

CRT . ,
dumb terminal (cpu, ram, disk ).
ethernet
.

TTY

251

Bash Shell Script

DEC VT100 terminal

,
1.
TTY

252

Bash Shell Script

[] 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

Bash Shell Script

Session management , job control . Ctrl-z


job suspend , Ctrl-c foreground job SIGINT
, foreground job , background job
SIGTTIN suspend TTY driver .
UART driver, Line discipline, TTY driver TTY device .

2. virtual console

[] http://www.linusakesson.net/programming/tty/
Ctrl-Alt-F1 ~ F6 OS .

emulation . Line discipline,


TTY driver getty login prompt
( ps ax | grep getty ). /dev/tty[] .

3. Pseudo TTY ( xterm, gnome-terminal, telnet, ssh ... )

TTY

254

Bash Shell Script

[] 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 .

( ssh client /dev/pts/ device


. )
xterm ls ptm -> line discipline -> pts bash (user process)
pts -> line discipline -> ptm xterm xterm
.

TTY

255

Bash Shell Script

[] 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

controlling terminal session leader . /dev/tty*


/dev/pts/* device .

session controlling terminal .

TTY

256

Bash Shell Script

controlling terminal session leader controlling process .


foreground process group background process groups
.
Ctrl-c SIGINT foreground process group .
modem (or network) SIGHUP controlling process (session leader)
.
ps ax TTY controlling terminal (ctty)

. ctty ? .

job control .

TTY

257

Bash Shell Script

Xterm bash (101) /dev/pts/0 ( controlling terminal )


. controlling process . job
sid (101) controlling terminal . Xterm (100)
PTM job /dev/pts/0 (PTS) .

/dev/tty
/dev/tty controlling terminal . ctty

/dev/pts/1 /dev/tty /dev/pts/1 . stdout, stderr


redirect /dev/tty .
/dev/tty open ctty .

Configuring TTY device


tty shell tty device , stty

TTY

258

Bash Shell Script

$ 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

UART parameters, line discipline, TTY driver


. speed UART parameters
pseudo terminal . rows, columns TTY driver
TTY driver
foreground job SIGWINCH . line line discipline 0 line
editing default discipline .
intr = ^C Ctrl-c
. dash ( - ) switch off . icanon line discipline
canonical (line-based) . stty -icanon off
cat[enter] backspace, ^U (Ctrl-u)
.
line discipline echo .
echo stty -echo echo .
job control tostop background job suspend
. off
stty tostop on suspend .
man , info .

Control Keys
^ .

TTY

259

Bash Shell Script

Ctrl
^M

^C (intr)

forground job SIGINT .

^D (eof)

cat, wc (
End Of File ) . ( master side
signal )

^\ (quit)

forground job SIGQUIT core dump


.
( ^C . )

^S (stop)

^Q (start)

DEL or ^? (erase)

^U

( )

^Z (susp)

forground job SIGTSTP suspend .

stdin, stdout, stderr


/dev/pts/ device controlling process
shell . shell /proc/$$/fd/ stdin,
stdout, stderr file descriptor 0, 1, 2 device
.

terminal 1 shell pid 123 terminal 2 terminal 1


/proc/123/fd/0 (stdin) /proc/123/fd/1 (stdout)
?

TTY

260

Bash Shell Script

# 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 # .

terminal 2 /proc/123/fd/0 terminal 1


hello read line . stdout .
terminal 1 stdout aaa terminal 2
/proc/123/fd/1 aaa . (
terminal 1 hello . )
stdin, stdout, stderr shell
.
f1 . echo, date
stdout
color escape stderr . stdout, stderr
?
f1() {
{ echo 111; date; echo 222 ;} & # background
{ echo -en "\e[31m"; sleep 1; echo -en "\e[m";} >&2
}

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

Bash Shell Script

HUP
HUP (hangup) .
, remote login ,
shell HUP . interactive shell HUP
stopped, running job HUP .

TTY

262

Bash Shell Script

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

Bash Shell Script

. 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

Bash Shell Script

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

Bash Shell Script

flock -u unlock .
critical section .
get_task_id ()
{
command ...
...
flock 9
...
# flock critical section
...
flock -u 9
...
...
} 9> "$lockfile"

mkdir flock . flock


-n ( nonblock ) lock
fail return . || exit .
#!/bin/bash
lockfile="/var/lock/$(basename "$0")"
exec 9> "$lockfile"
flock -n 9 || exit 1
trap 'rm -f "$lockfile"' EXIT
command1 ...
command2 ...
command3 ...

flock
flock file descriptor .
flock lock
. lock file descriptor
.

Mutual Exclusion

266

Bash Shell Script

# 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 .

flock -n -o /var/lock/mylock ./script.sh

lockfile
flock file descriptor lock
. (lockfile) A, B, C
lockfile file descriptor lock
.

Mutual Exclusion

267

Bash Shell Script

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

Bash Shell Script

Signals and Traps


Signal software interrupt . OS
system events .
ctrl-c , signal
( or ) ,
signal .

Signal sending
.

. .
OS PCB (Process Control Block)
.

Operating System scheduling


Signal receiving OS scheduling .
cpu 2 . cpu
( cpu burst ) I/O wait ( I/O burst ) . process A
I/O wait cpu idle OS process B
.
cpu process A process B context switching
process A cpu ( register )
process B cpu . core cpu
,
context swtching .

Signals and Traps

269

Bash Shell Script

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 ) .

Signals and Traps

270

Bash Shell Script

ready queue running PCB


. KILL INT handler
running .

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 .

Signals and Traps

271

Bash Shell Script

a.sh, b.sh, c.sh INT PCB c.sh OS


b.sh handler . b.sh
a.sh handler a.sh .
handler default handler bash sh
. c.sh sleep ctrl-c .
1. a.sh, b.sh, c.sh default handler ( trap )
a.sh : default INT handler
b.sh : default INT handler
c.sh : default INT handler

2. a.sh default handler, b.sh handler, c.sh default handler


a.sh : ( sh : default handler )
b.sh : INT handler
c.sh : default INT handler

3. a.sh, b.sh default handler, c.sh handler


a.sh : ( sh : default handler )
b.sh : ( sh : default handler )
c.sh : INT handler

4. a.sh handler, b.sh default handler, c.sh handler


a.sh : INT handler
b.sh : ( sh : default handler )
c.sh : INT handler

5. a.sh, b.sh, c.sh handler


a.sh : INT handler
b.sh : INT handler
c.sh : INT handler

Ignore
trap ignore child . a.sh
INT ignore b.sh, c.sh INT handler default handler
. interactive shell SIGTSTP, SIGTTIN, SIGTTOU
ignore trap .

Signals and Traps

272

Bash Shell Script

# 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

Signals and Traps

273

Bash Shell Script

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 process group . pgid -


.
kill -TERM -4287

kill -0 pid
kill -0 ,

kill

274

Bash Shell Script

$ kill -0 32630; echo $?


0 # process
$ kill -0 32631; echo $?
bash: kill: (32631) - No such process # process
1
$ kill -0 1; echo $?
bash: kill: (1) - Operation not permitted # process .
1

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

Bash Shell Script

trap
trap [-lp] [[arg] signal_spec ...]

.
Ctrl-c ,
.
trap
.
signal handler
trap 'myhandler' EXIT
myhandler() { ... ;}

handler default reset


trap - INT

signal ignore handler


trap '' INT


default handler

trap
3 trap ignore signal handler
. default handler .
SIGKILL
SIGSTOP
SIGCONT

Pseudo signals
trap

276

Bash Shell Script

trap signal table


Termination Signals, Job Control Signals . table
handler HUP, INT, QUIT, TERM
.
.
#!/bin/bash
trap 'myhandler' HUP INT QUIT TERM
myhandler() { ... ;}
...
...
...
myhandler #

shell EXIT pseudo-signal . trap EXIT


handler . , Ctrl-c
, , shutdown exit
. EXIT .
#!/bin/bash
trap 'myhandler' EXIT
myhandler() { ... ;}
...
...

Shell pseudo-signals EXIT source return


RETURN , 0 ERR ,
DEBUG . subshell
( functrace, errtrace ), child process .
Signal

Description

EXIT

shell exit . ( subshell )

ERR

0 .

DEBUG
RETURN

.
, source .

RETURN

trap

277

Bash Shell Script

#!/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

Bash Shell Script

# .
#!/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

bash EXIT handler


.
#!/bin/sh
trap 'exit' HUP INT QUIT TERM
trap 'rm -f /tmp/file' EXIT

trap handler quotes


trap handler double quotes
.
------------- trap1.sh ------------#!/bin/bash
AA=100
trap "echo $AA" EXIT # double quotes
AA=200
------------- trap2.sh ------------#!/bin/bash
AA=100
trap 'echo $AA' EXIT # single quotes
AA=200
-------------- ---------------$ ./trap1.sh
100
$ ./trap2.sh
200

trap handler shell .


trap

279

Bash Shell Script

#!/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

Bash Shell Script

------- A.sh ------#!/bin/bash


echo A.sh --- start
./B.sh
echo A.sh --- end
-------- B.sh -------#!/bin/bash
echo B.sh ------ start
sleep 100
echo B.sh ------ end
---------------------$ ./A.sh
A.sh --- start
B.sh ------ start
^C # Ctrl-c A.sh, B.sh .

child process . B.sh trap


exit . A.sh Ctrl-c A.sh
child process B.sh A.sh A.sh --end .

trap

281

Bash Shell Script

------- B.sh ------#!/bin/bash


trap 'echo trap INT in B.sh; exit' INT
echo B.sh ------ start
sleep 100
echo B.sh ------ end
--------------------$ ./A.sh
A.sh --- start
B.sh ------ start
^Ctrap INT in B.sh
A.sh --- end # B.sh A.sh .

########## #!/bin/sh #########


sh A.sh default INT handler
`trap ':' INT` .
------- A.sh ------#!/bin/sh
trap ':' INT
echo A.sh --- start
./B.sh
echo A.sh --- end
-------- B.sh -------#!/bin/sh
echo B.sh ------ start
sleep 100
echo B.sh ------ end

ping . B.sh ping


Ctrl-c ping B.sh, A.sh
. ping trap trap
'command ... ; exit' INT .

trap

282

Bash Shell Script

------- B.sh ------#!/bin/bash


echo B.sh ------ start
ping 1.1.1.0
echo B.sh ------ end
--------------------$ ./A.sh
A.sh --- start
B.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
B.sh ------ end # ping B.sh, A.sh .
A.sh --- end

ping Ctrl-c ping B.sh,


A.sh . bash
handler default handler
( shebang #!/bin/sh B.sh, A.sh )
trap exit , trap reset ( trap - INT )
INT B.sh, A.sh default INT handler
.
------- B.sh ------#!/bin/bash
trap 'echo trap INT in B.sh; trap - INT; kill -INT $$' INT
echo B.sh ------ start
ping 1.1.1.0
echo B.sh ------ end
--------------------$ ./A.sh
A.sh --- start
B.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 INT in B.sh # ping A.sh, B.sh .

trap

283

Bash Shell Script

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

########## #!/bin/sh ##########


sh default INT handler
trap .
------- A.sh ------#!/bin/sh
echo A.sh --- start
ping 1.1
echo A.sh --- end
--------------------

PGID child process


a.sh -> b.sh -> c.sh -> d.sh sleep Ctrl-c
tty driver INT foreground process group 4
. b.sh c.sh pgid c.sh
d.sh a.sh, b.sh . ( c.sh, d.sh
foreground process group )
shell setsid sid, pgid setpgid
. set -o monitor
pgid .

trap

284

Bash Shell Script

---------- b.sh --------#!/bin/bash


...
...
set -o monitor
./c.sh # c.sh pgid
...

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

INT trap cat trap handler


echo 111 .
$ ( trap 'echo exit : $?' INT; cat; echo 111 ) # INT
^Cexit : 130
111

trap handler .
$ ( trap 'exit 0' INT; cat ); echo exit : $?
^Cexit : 0

trap

285

Bash Shell Script

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)

illegal, malformed, unknown, or


privileged instruction
.

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)

software emulation instruction


OS emulation
.

SIGSYS

n/a

Terminate
(core dump)

system call
. system call libc
.

SIGFPE

SIGILL

Num

Termination Signals

Signals Table

286

Bash Shell Script

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

real or clock alarm or


setitimer function
.

SIGVTALRM

n/a

Terminate

CPU alarm or
setitimer function
.

Terminate

cpu
system call cpu
alarm or setitimer function
. code profiling
.

SIGPROF

n/a

Asynchronous I/O Signals

Signals Table

287

Bash Shell Script

Signal

Num

DefaultAction

Description

SIGIO

n/a

Ignore

socket FD (file descriptor)


input output .
kernel caller FD
I/O requests
.

SIGURG

n/a

Ignore

socket urgent or out-of-band


.

SIGPOLL

n/a

Ignore

System V SIGIO . (
)

Job Control Signals


Signal

Num

DefaultAction

Description

SIGCHLD

n/a

Ignore

child terminate, stop, continue


parent .

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

background process tty


.

SIGTTOU

n/a

Stop

background process tty


. tostop enable
. ( stty -a )

Operation Error Signals

Signals Table

288

Bash Shell Script

Signal

SIGPIPE

SIGLOST

Num

DefaultAction

Description

Terminate

broken pipe . writer


reader
connect socket
.

Terminate

Resource lost . NFS


lock NFS reboot
lock
.

n/a

n/a

SIGXCPU

n/a

Terminate

CPU ( soft limit )



OS SIGKILL
.

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

foreground process group


group leader

.

SIGINFO

n/a

Description

Real time Signals


SIGRTMIN ~ SIGRTMAX real time signal .
RTS
queue .
RTS ,
. RTS polling
. queue
.

Signals Table

289

Bash Shell Script

Num
. POSIX standard
OS .

DefaultAction
Terminate
.
Terminate (core dump)
core .
Ignore
.
Stop
stop . ( . )
Continue
stopped . ( . )

Signals Table

290

Bash Shell Script

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 .

xtrace, verbose turn off .


set - 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

Bash Shell Script

functions, variables export child process .

-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

Bash Shell Script

ctrl-d end of file


. ctrl-d exit
$IGNOREEOF . ( 10 10 ctrl-d
exit . )

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

Bash Shell Script

background process stop


. .

-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

Bash Shell Script

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

Bash Shell Script

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 .

( $PATH ) No such file or directory .


hash table $PATH .

checkjobs
exit background job table stopped job
There are stopped jobs . running job
. running job .
exit stopped job running
job background .

Shell Options

296

Bash Shell Script

$ ping 192.168.1.1 &


[1] 1736
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
$ shopt -s checkjobs
$ exit
exit
There are running jobs. # running job .
[1]+ Running ping 192.168.1.1 &

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

Bash Shell Script

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

Bash Shell Script

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

DEBUG trap 2 source


.
BASH_ARGC BASH_ARGV .

extglob
Globbing extended pattern matching .

extquote
Parameter expansion $'string' and $"string" .
.

Shell Options

299

Bash Shell Script

$ shopt -u extquote ; var=


$ echo "${var:-$"translate me"}"
me
$ echo "${var:-$'ab\ncd'}"
$'ab\ncd' # $
$ shopt -s extquote
$ echo "${var:-$"translate me"}"
translate me
$ echo "${var:-$'ab\ncd'}"
ab
cd

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

Bash Shell Script

shell exit HISTFILE history list append . off


overwrite .

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

Bash Shell Script

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

Bash Shell Script

shift_verbose
shift shift count positional parameters
.

sourcepath
source $PATH . .

xpg_echo
echo single, double quotes escape sequences
.

Shell Options

303

Bash Shell Script

Bourne Shell Variables


CDPATH
: cd
tab .
$ echo $CDPATH
.:/home/razvan/school/current:/home/razvan/projects
$ pwd
/home/razvan
$ cd so
/home/razvan/school/current/so
$ cd p2p-next
/home/razvan/projects/p2p-next

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

Bash Shell Script

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

Bash Shell Script

BASHOPTS
shopt : .

BASHPID
bash process id . subshell .

BASH_ALIASES
alias associative array .

BASH_ARGC
shopt -s extdebug call stack

array . func1 11 func2 22 33


${BASH_ARGC[@]} 2 1 .

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 Shell Script

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 Shell Script

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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

filename expansion and pattern matching .

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

Bash Shell Script

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 .

ramesh@dev-db ~> export PROMPT_COMMAND="date +%k:%m:%S; date;"


19:06:44
Thu Jun 11 19:14:44 KST 2015
ramesh@dev-db ~>
19:06:47
Thu Jun 11 19:14:47 KST 2015
ramesh@dev-db ~>

PROMPT_DIRTRIM

... .

PS3
select .

PS4
-x | set -o xtrace
, . PS4
. + .

Shell Variables

314

Bash Shell Script

# 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

Bash Shell Script

bash process . bash SHLVL 2


. shell script , bash -c 'echo $SHLVL'
. child process subshell .
subshell BASH_SUBSHELL .
$ echo $SHLVL
1
$ bash
$ echo $SHLVL
2

TIMEFORMAT
time .

TMOUT
read , select .

.
exit .

TMPDIR
shell .

UID
numeric real user id readonly . login id
.

Shell Variables

316

Bash Shell Script

Positional Parameters

function
source
positional paramters .
$1 , $2 ... scope local . sh
array .

$0
.
bash -c .

$ bash -c 'echo $0, $1, $2' 11 22 33


11, 22, 33

$#
$0 .

$1, $2, $3 ...


.

Positional Parameters

317

Bash Shell Script

--------- test.sh -------#!/bin/sh


echo number of arguments = $#
echo \$0 = "$0"
echo \$1 = "$1"
echo \$2 = "$2"
echo \$3 = "$3"

######### output ########


$ ./test.sh 11 22 33
number of arguments = 3
$0 = ./test.sh
$1 = 11
$2 = 22
$3 = 33

$@ , $*
$@ , $* positional parameters . array @ , *

. quote
quote "$@" "$1" "$2" "$3" ... "$*"
"$1c$2c$3 ... " . ( c IFS . )

Positional Parameters

318

Bash Shell Script

--------- test.sh -------#!/bin/sh


echo \$@ : $@
echo \$* : $*
echo '======== "$@" ======='
for v in "$@"; do # for v do ...
echo "$v"
done
echo '======== "$*" ======='
for v in "$*"; do
echo "$v"
done
########### output ##########
$ ./test.sh 11 22 33
$@ : 11 22 33
$* : 11 22 33
======== "$@" =======
11
22
33
======== "$*" =======
11 22 33
----------------------------$ f1() { "$@" ;}
$ f1 date +%D
01/22/16
$ f1() { "$*" ;}
$ f1 date +%D
date +%D: command not found # 'date +%D' .

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

Bash Shell Script

--------- test.sh -------#!/bin/sh


# set script positional parameters
set -- 11 22 33
echo number of arguments = $#
echo \$0 = "$0"
echo \$1 = "$1"
echo \$2 = "$2"
echo \$3 = "$3"
######### output ########
$ ./test.sh
number of arguments = 3
$0 = ./test.sh
$1 = 11
$2 = 22
$3 = 33

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

Bash Shell Script

#!/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

Bash Shell Script

Special Parameters
$?
.

$$
shell process id . subshell .

$!
& background process id .
| process id .

$_
. .

$Set shell enable option flags .

Special Parameters

322

Bash Shell Script

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 .
}

BASH_ALIASES associative array alias .

Command Aliases

323

Bash Shell Script

$ alias p3='ps afo user,ppid,pid,pgid,sid,tty,stat,args'


$ echo "${BASH_ALIASES[p3]}"
ps afo user,ppid,pid,pgid,sid,tty,stat,args

alias .
alias escape \ quote .
command , builtin .

alias unalias .

Command Aliases

324

Bash Shell Script

Command History
interactive shell history .
history .
history list . shopt
-s histappend $HISTFILE history list .

Non-interactive shell disable .


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

Bash Shell Script

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

Bash Shell Script


: . 0
1, 2, 3 ... .

command arg1 arg2 arg3 arg4 arg5

$ !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

Bash Shell Script

$ 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

Bash Shell Script


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

Bash Shell Script


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

Bash Shell Script

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

Bash Shell Script

history list history file read write


history .

-c
-d offset

history list .
offset .

-r

history file history list append

-n

history file .

-a

history list history file append .

-w

history list history file write .

Command History

332

Bash Shell Script

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

Bash Shell Script

# 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

Bash Shell Script

action
-a | alias

alias

arrayvar

array

binding

Readline key binding .

-b | builtin

Shell builtin .

-c | command

(builtin ).

-d | directory

.
FIGNORE .

disabled

Disable shell builtin .

enabled

Enable shell builtin .

-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

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

$ complete -W 'aaa bbb ccc' hello


# .
$ hello aaa [stop]
# -o nospace
$ complete -o nospace -W 'aaa bbb ccc' hello
# .
$ hello aaa[stop]

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

Bash Shell Script

$ complete -W 'aaa.x bbb.y ccc.z' -X "*.z" hello


$ hello # '*.z' 'ccc.z' .
aaa.x bbb.y

-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

shell interactive shell ( alias,


command history, job control enabled ). alias
.


$1 , $2 , $3 .

mycomm ubuntu fedora arch[tab]


\ | \
\_ $1 |_ $3 \_ $2
(command) (previous) (current)

Command Completion

339

Bash Shell Script

current " $2 " .


${COMP_WORDS[COMP_CWORD]} .

.
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

Bash Shell Script

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

Virtualbox Bash Completion


vboxmanage
.
https://github.com/mug896/virtualbox-bash-completion

Command Completion

341

Bash Shell Script

Command Completion

342

Bash Shell Script

Readline
CLI (command line interface) line editing, history,
shell ,
history, . line editing emacs vi
emacs set -o emacs or set -o vi
.

Readline init file


readline ~/.inputrc
. completion-ignore-case tab alt-/
, alt-space "git " ctrl-space "docker "
F9 , F10 .
read .
^[ \e .
$ read # enter
^[[20~ # F9

inputrc Ctrl-x Ctrl-r

. window manager
.

~/.inputrc

Readline

343

Bash Shell Script

# , 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

Bash Shell Script

$ sudo apt-get install rlwrap


$ rlwrap ed -p :

Readline

345

Bash Shell Script

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

Bash Shell Script

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

Bash Shell Script

### trace : xtrace.sh


#!/bin/bash
AA="foo bar"
if [ $AA = "foo bar" ]; then
echo same !!!
else
echo not same !!!
fi
###
$ ./xtrace.sh
$ ./xtrace.sh: line 14: [: too many arguments
not same !!!
### xtrace
$ bash -x ./xtrace.sh
+ BB='foo bar'
+ '[' foo bar = 'foo bar' ']' # AA foo bar .
./xtrace.sh: line 14: [: too many arguments
+ echo not same '!!!'
not same !!!
### $AA "$AA" quote
$ bash -x ./xtrace.sh
+ BB='foo bar'
+ '[' 'foo bar' = 'foo bar' ']' # AA 'foo bar' .
+ echo same '!!!'
same !!! # .

xtrace $ .
echo echo trace . colon
: . :

Debugging

348

Bash Shell Script

#!/ 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

Bash Shell Script

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

Bash Shell Script

#!/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

if, while, &&, || ERR trap .


if, while, &&, || trap .
# &&, ||
./error_command.sh || true
# if
if ./error_command.sh; then
:
else
:
fi

trap .
./error_command.sh
[ $? -eq 0 ] && echo true
./error_command.sh
if [ $? -eq 0 ]; then
...

ERR trap
0 false 1 .

Debugging

351

Bash Shell Script

# 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

&& , || ERR trap trap .


# test && trap .
test -d nosuchdir && ...
# trap .
f1() { test -d nosuchdir && ... ;}
f1

read -d null end-of-file .

Debugging

352

Bash Shell Script

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 .
++ , --

sh$ : $(( i++ ))


sh: 2: arithmetic expression: expecting primary: " i++ " #
# .
i=$((i+1)) i=$((i-1))
: $((i+=1)) : $((i-=1))

Dash

353

Bash Shell Script

sh$ : $(( i+=1, i+=1 ))


sh: 21: arithmetic expression: expecting EOF: " i+=1 , i+=1 " #

**

sh$ echo $(( 2**3 ))


sh: 363: arithmetic expression: expecting primary: " 2**3 " #

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

Bash Shell Script

<<
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 Shell Script

bash dash .

+=
+= . .

### bash ###


bash$ AA=hello
bash$ AA+=" World"
bash$ echo "$AA"
hello World
### dash ###
sh$ AA=hello
sh$ AA="$AA World" # "$AA"" World"
sh$ echo "$AA"
hello World

$' ' , $" "


bashism .

Array
Array POSIX indexed array, associative array
AA=() . positional parameters
.

Dash

356

Bash Shell Script

#!/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

Bash Shell Script

function myfunc() { ... ;} # function


myfunc() { ... ;} #

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

Bash Shell Script

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
.

Color escape sequence


color escape sequence
.

1. escape
escape .
\e , \x1b (16) , \033 (8)

2. [
.

3. style; foreground; background


style .

4. m

Colors and Prompt

359

Bash Shell Script

)
# \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 .
.

Colors and Prompt

360

Bash Shell Script

# 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

Colors and Prompt

361

Bash Shell Script

#!/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
.

Colors and Prompt

362

Bash Shell Script

# 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 .
.

Colors and Prompt

363

Bash Shell Script

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"\"

Colors and Prompt

364

Bash Shell Script

prompt PS1="hello \w $? > "


double quotes $?
. prompt $?
single quotes .
AA=hello
PS1="$AA \w "'$?'" > "

prompt escape sequences \$ double quotes $ escape


single quotes .
AA=hello
PS1="$AA \w "'$? \$ '

color escape sequences non-printing prompt \[ \]


.
AA=hello
color_reset="\[\e[0m\]"
color_f_red="\[\e[0;31m\]"
PS1="$AA \w $color_f_red"'$?'"$color_reset"' \$ '
------------------------------------------------color_reset="\[$(tput sgr0)\]"
color_f_red="$color_reset\[$(tput setaf 1)\]"
PS1="$AA \w $color_f_red"'$?'"$color_reset"' \$ '

Prompt Escape Sequences

Colors and Prompt

365

Bash Shell Script

Code

Description

\a

an ASCII bell (07)

\d

"Weekday Month Date" (e.g., "Tue May 26")

\D{format}

strftime(3) format . { }
\D{} empty
.

\e

an ASCII escape (033)

\h

the hostname ' . '

\H

the hostname

\j

background jobs

\l

shell terminal device (tty5)

\n

newline

\r

carriage return

\s

shell ( the basename of $0 )

\t

( 24-hour HH:MM:SS )

\T

( 12-hour HH:MM:SS )

\@

( 12-hour am/pm )

\A

( 24-hour HH:MM )

\u

username

\v

the version of bash (e.g., 2.00)

\V

the release of bash, version + patch level (e.g., 2.00.0)

\w

working directory ( $HOME ' ~ ' )

\W

working directory basename ( $HOME ' ~ ' )

\!

history number

\#

command number
( enter )

\$

effective UID 0 '#' '$'

\nnn

\\

a backslash

\[

non-printing sequence
( color escape sequence )

\]

non-printing sequence

Colors and Prompt

366

Bash Shell Script

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

Bash Shell Script

$ echo -n "$IFS" | od -a # read IFS


0000000 sp ht nl
# IFS read ':'
$ IFS=: read -ra arr <<< "Arch Linux:Ubuntu Linux:Suse Linux"
$ echo "${arr[1]}" # .
Ubuntu Linux
$ echo -n "$IFS" | od -a # read IFS
0000000 sp ht nl # .

.
. 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

Bash Shell Script

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

Вам также может понравиться