Skip to content

Latest commit

Β 

History

History
2611 lines (2005 loc) Β· 78.5 KB

README.md

File metadata and controls

2611 lines (2005 loc) Β· 78.5 KB

Abstract

bash reference manual | gnu 을 읽고 μ •λ¦¬ν•œλ‹€.

References

Shell Metachars

metachars λŠ” command 와 λ‹€λ₯΄κ²Œ 처리되기 λ•Œλ¬Έμ— command line 에 ν¬ν•¨ν•˜λŠ” 경우 escape ν•˜κ±°λ‚˜ quote ν•΄μ„œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

(    )    `    |    &    ;        # Command substitution
&&   ||                           # AND, OR 
<    >    >>                      # Redirection 
*    ?    [     ]                 # Glob 
"    '                            # Quote 
\    $      
=    +=                            

Basic Usages

$ bash  # From zsh

# help (shell builtin)
# Display helpful information about builtin commands.
$ help  
$ help echo
# Display the possible completions depending on the options.
$ help compgen
# Run a shell builtin. 
$ help builtin

# type (shell builtin)
# For each NAME, indicate how it would be interpreted 
# if used as a command name.
$ help type  # bash-builtin
$ type ssh
ssh is /usr/bin/ssh
$ type caller
caller is a shell builtin
$ type time
time is a shell keyword
$ type compgen
compgen is a shell builtin
$ type builtin
builtin is a shell builtin

# command (shell builtin)
# Runs COMMAND with ARGS ignoring shell functions.
# Check whether the command is installed.
$ command -v git-lfs
/usr/local/bin/git-lfs

# compgen (shell builtin)
# Display the possible completions depending on the options.
# Show keywords
$ compgen -k | column
if              elif            esac            while           done            time            !               coproc
then            fi              for             until           in              {               [[
else            case            select          do              function        }               ]]

# Show builtins
$ compgen -b | column
.               caller          dirs            false           kill            pwd             source          ulimit
:               cd              disown          fc              let             read            suspend         umask
[               command         echo            fg              local           readarray       test            unalias
alias           compgen         enable          getopts         logout          readonly        times           unset
bg              complete        eval            hash            mapfile         return          trap            wait
bind            compopt         exec            help            popd            set             true
break           continue        exit            history         printf          shift           type
builtin         declare         export          jobs            pushd           shopt           typeset

# File name can be anything except "NUL, /" on linux
$ echo "hello world" > [[]].txt

# '-' can be stdin for input
$ echo hello world | cat -
# '-' can be stdout for output
$ echo hello world | cat a.txt -
$ seq 10 | paste - - -

# > 
# Redirect the stdout of a command to a file. 
# Overwrite the file if it already exists.
$ echo "foo" > a.txt

# <
# Redirect file contents to stdin of command.
$ cat < a.txt

# >>
# Redirect and append stdout of a command to a file
$ echo "foo" >> a.txt

# 2>
# Redirect the stderr of a command to a file
$ echo "foo" 2> a.txt
$ abc 2> a.txt || cat a.txt
bash: abc: command not found

# 2>>
# redirect and append the stderr of a command to a file
$ echo "foo" 2>> a.txt

# &>
# redirect stdout, stderr of a command to a file
$ echo "foo" &> a.txt
$ abc &> a.txt || cat a.txt
bash: abc: command not found

# 1>&2
# Redirect stdout of a command to stderr
foo=$(echo "foo" 1>&2)
$ echo $foo

# 2>&1
# Redirect stderr of a command to stdout
$ foo > /dev/null
bash: foo: command not found
$ foo > /dev/null 2>&1
$ foo 2> /dev/null

# |
# Redirect stdout of first command to stdin of other command
$ ls -al | grep foo

# $
$ foo="hello world"
$ echo $foo

# ``
# Command substitution
$ echo `date`

# $()
# The alternative form of command substitution
$ echo $(date)

# &&, ||
# Execute several commands
#
# If 1st command result is true, run 2nd command.
# If 1st command result is false, done.
$ make && make install           
# If 1st command result is true, done.
# If 1st command result is false, run 2nd command.
$ echo "hello" || echo "world"   

# ;
# Execute several commands on a line
$ false; echo "foo"

# ''
# Full quoting (single quoting)
# 'STRING' preserves all special characters within STRING. 
# This is a stronger form of quoting than "STRING".
$ echo '$USER'
$USER
$ echo "$USER"
davidsun

# ""
# Partial quoting (double quoting)
# "STRING" preserves (from interpretation) 
# most of the special characters within STRING.
# except "$, `, \"
$ echo "foo"
$ echo "$USER"
$ echo "Now is $(date)"
Now is 2023λ…„ 7μ›” 25일 ν™”μš”μΌ 17μ‹œ 04λΆ„ 33초 KST
$ echo "Now is `date`"
Now is 2023λ…„ 7μ›” 25일 ν™”μš”μΌ 17μ‹œ 04λΆ„ 33초 KST

# "''"
$ bash -c "/bin/echo foo 'bar'"
foo bar

# \" \$foo
$ bash -c "/bin/echo '{ \"user\" : \"$USER\" }'"
{ "user" : "david.s" }
$ echo "\$foo \" \`"
$foo " `

# $
# Variable substitution
$ msg="bar"
$ echo "foo $msg"

# ${}
# Parameter substitution
# The status of variable can be unset, NUL, set.
# :- for unset, NUL
# -  for unset
#
# foo is unset
$ unset foo 
$ echo ${foo:-"aaa"}
aaa
$ echo ${foo-"aaa"}
aaa
# foo is NUL
$ foo= 
$ echo ${foo:-"aaa"}
aaa
$ echo ${foo-"aaa"}

# \
# Represent a command in several lines
$ echo "foo"
$ echo \
  "foo"

# Brace expansion
# {1..10}
# 
$ echo {1..10}
# {string1,string2}
#
$ cp {foo.txt,bar.txt} a/

# Looping constructs
# until, while, for, break, continue
$ until test-commands; do consequent-commands; done
$ while test-commands; do consequent-commands; done
$ for name [ [in [words …] ] ; ] do commands; done
$ for (( expr1 ; expr2 ; expr3 )) ; do commands ; done

# while..do..done
while true
do
  echo "foo"
  sleep 1
done
while true; do echo "foo"; sleep 1; done

# for..do..done
for i in {1..10}
do 
  echo ${i}
done
for i in {1..10}; do echo ${i}; done

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

NUM=(1 2 3)
for i in ${NUM[@]}
do
  echo ${i}
done
for i in ${NUM[@]}; do echo ${i}; done

# Conditional consructs:
#   if, case, select, ((...)), [[...]]

# if
# comparison of numbers
# -eq, -ne, -gt, -ge, -lt, -le
# comparison of strings
# =(==), !=, -z(null), -n(not null)
if [ $a -eq $b ]; then
  echo $a
fi

# Grouping commands : (), {}
# (command line) : command line execute on subshell environment.
$ ( while true; do echo `date`; sleep 1; done )
$ pstree
# {command line} : command line execute on same shell environment.
$ { while true; do echo `date`; sleep 1; done }
$ pstree

# The status of variable can be unset, null, not-null.
# unset state
$ declare A
$ local A
# null state
$ A=
$ A=""
$ A=''
# not-null state
$ A=" "
$ A="hello"
$ A=123

# function 은 command 듀을 κ·Έλ£Ήν™” ν•˜λŠ” 방법이닀. 그룹의 이름을 μ‚¬μš©ν•˜λ©΄ 
# κ·Έλ£Ήμ•ˆμ˜ commandsλ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€.
# name () compound-command [ redirections ]
$ H() { echo "hello"; }; H; echo "world";
# function name [()] compound-command [ redirections ]
$ function H() { echo "hello"; }; H; echo "world";

# '*', '?', '[]' κ³Ό 같은 glob characters 을 μ΄μš©ν•˜μ—¬ filename, case, 
# parameter expansion, [[]] expression λ“±μ—μ„œ pattern matching 이 
# κ°€λŠ₯ν•˜λ‹€.
# filename
$ ls *.[ch]
# [[]] expression
$ [[ $A = *.tar.gz ]]; echo $?
$ [[ $A = *dog\ cat* ]]; echo $?

# shell file 의 μ²«μ€„μ—μ„œ 슀크립트λ₯Ό μ‹€ν–‰ν•  command line 을 
# shabang line 이라고 ν•œλ‹€. μ˜΅μ…˜μ€ ν•˜λ‚˜λ‘œ μ œν•œλœλ‹€.
#!/bin/bash
#!/bin/sed -f
#!/usr/bin/awk -f
#!/usr/bin/perl -T

# env λŠ” PATH ν™˜κ²½λ³€μˆ˜μ—μ„œ python 을 찾아보고 μžˆλ‹€λ©΄ μ‹€ν–‰ν•œλ‹€.
# python 이 어디에 μ„€μΉ˜λ˜μ–΄ 있던 PATH ν™˜κ²½λ³€μˆ˜μ—μ„œ κ²€μƒ‰λ§Œ 되면
# μ‹€ν–‰ν•  수 μžˆλ‹€. μ‹œμŠ€ν…œμ— 쒅속적이지 μ•Šλ‹€.
# execvp() 둜 program name 을 μ‹€ν–‰ν•œλ‹€.
# execvp() λŠ” ν”„λ‘œκ·Έλž¨μ„ PATH μ—μ„œ κ²€μƒ‰ν•˜μ—¬ μ‹€ν–‰ν•œλ‹€.
# https://github.com/coreutils/coreutils/blob/master/src/env.c
#!/usr/bin/env python

# <<<
# Redirect a string to stdin of a command
$ cat <<< "I am $USER"

# <<EOF EOF
# Redirect several lines to stdin of a command
$ cat > a.txt <<EOF
I am the man.
HOST is ${HOSTNAME}
USER is ${USER}
EOF

# export
$ export foo=bar

# printf
$ Message1="foo"
$ Message2="bar
$ printf "%s %s \n" $Message1 $Message2

# sed
$ sed -i "s/foo/bar/g" a.txt

Basic Shell Features

Shell Syntax

Shell Operation

shell 이 command λ₯Ό 읽고 μ‹€ν–‰ν•˜λŠ” 과정은 λ‹€μŒκ³Ό κ°™λ‹€.

  • commands 및 arguments λ₯Ό 읽어 듀인닀.
  • 읽어 듀인 commands λ₯Ό quoting κ³Ό λ™μ‹œμ— metacharaters λ₯Ό κ΅¬λΆ„μžλ‘œ words 와 operators 둜 μͺΌκ° λ‹€. μ΄λ•Œ alias expansion 이 μˆ˜ν–‰λœλ‹€.
  • 토큰듀을 μ½μ–΄μ„œ simple, compound commands λ₯Ό κ΅¬μ„±ν•œλ‹€.
  • λ‹€μ–‘ν•œ shell expansion 이 μˆ˜ν–‰λ˜κ³  expanded tokens λŠ” νŒŒμΌμ΄λ¦„, μ»€λ§¨λ“œ, 인자둜 κ΅¬μ„±λœλ‹€.
  • redirection 을 μˆ˜ν–‰ν•˜κ³  redirection operators 와 operands λ₯Ό argument list μ—μ„œ μ œκ±°ν•œλ‹€.
  • command λ₯Ό μ‹€ν–‰ν•œλ‹€.
  • ν•„μš”ν•œ 경우 command κ°€ μ‹€ν–‰ μ™„λ£Œλ  λ•ŒκΉŒμ§€ 기닀리고 exit status λ₯Ό μˆ˜μ§‘ν•œλ‹€.

Quoting

Escape Character

The escape character (\) is used to remove the special meaning of the character immediately after it.

$ echo "This is a quote: \""
This is a quote: "

Single Quotes

Single quotes (') preserve the literal value of each character within the quotes.

$ echo 'Hello, $USER!'
Hello, $USER!

Double Quotes

Double quotes (") preserve the literal value of all characters within the quotes, except for $, `` , and \.

$ echo "Hello, $USER!"
Hello, <username>!

ANSI-C Quoting

Using $'' allows interpreting certain escaped characters according to the ANSI-C standard.

$ echo $'Hello,\nWorld!'
Hello,
World!

Locale-Specific Translation

Using $"" allows translating strings according to the current locale settings.

# assuming a Spanish locale
$ echo $"Hello, World!"
Β‘Hola, Mundo!

Comments

Comments start with the # character and continue until the end of the line.

# This is a comment
echo "This is not a comment"

Shell Commands

Reserved Words

There are reserved words such as if, then, else, elif, fi, case, esac, for, select, while, until, do, done, in, function.

if [ $USER == "root" ]; then
  echo "You are the root user"
fi

Simple Commands

A simple command is a sequence of words separated by spaces or tabs.

$ ls -l

Pipelines

A pipeline is a sequence of commands separated by the | operator. The output of the first command is passed as input to the second command.

$ ls -l | grep ".txt"

Lists of Commands

Lists of commands are sequences of commands that are executed sequentially, possibly separated by the ;, &, &&, or || operators.

$ echo "Hello,"; echo " World!"

Compound Commands

Looping Constructs

There are several looping constructs: for, while, until.

for i in {1..3}; do
  echo "$i"
done

Conditional Constructs

Several conditional constructs, like the if, else, elif branches, and case statements.

number=5
if [ $number -eq 3 ]; then
  echo "Number is 3"
elif [ $number -eq 5 ]; then
  echo "Number is 5"
else
  echo "Number is not 3 or 5"
fi

Grouping Commands

Grouping commands can be done with {} or ().

  • {} execute commands in same shell.
  • () execute commands in subshell.
$ { echo "Hello,"; echo " World!"; }

child shell vs subshell

μžμ‹ μ‰˜κ³Ό μ„œλΈŒ μ‰˜μ˜ 차이에 λŒ€ν•œ μš”μ•½κ³Ό μ˜ˆμ œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • μžμ‹ μ‰˜ (child shell) : μžμ‹ μ‰˜μ€ λΆ€λͺ¨ μ‰˜μ˜ λΆ€λΆ„ λ³΅μ‚¬λ³Έμž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, λΆ€λͺ¨ μ‰˜μ˜ ν™˜κ²½ λ³€μˆ˜λŠ” λ³΅μ‚¬λ˜μ§€λ§Œ, λΆ€λͺ¨ μ‰˜μ˜ 둜컬(내보내지 μ•Šμ€) λ³€μˆ˜λ‚˜ 별칭은 λ³΅μ‚¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μƒˆλ‘œμš΄ μžμ‹ μ‰˜μ΄ μ‹€ν–‰λ˜κ³  별칭이 μ—†μœΌλ©° ν™˜κ²½ λ³€μˆ˜λ§Œ μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€.
    $ alias
    alias gd='pushd' alias l='ls -CF' alias pd='popd'
    $ bash --norc
    $ alias
    $ echo $HOME
    /home/smith
    $ exit
  • μ„œλΈŒ μ‰˜ (subshell) : μ„œλΈŒ μ‰˜μ€ λΆ€λͺ¨ μ‰˜μ˜ μ™„μ „ν•œ λ³΅μ‚¬λ³Έμž…λ‹ˆλ‹€. λΆ€λͺ¨ μ‰˜μ˜ λͺ¨λ“  λ³€μˆ˜, 별칭, ν•¨μˆ˜ 등을 ν¬ν•¨ν•˜λ©°, κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹€ν–‰ν•©λ‹ˆλ‹€. μ„œλΈŒ μ‰˜μ—μ„œ μ‹€ν–‰λœ λͺ…령은 λΆ€λͺ¨ μ‰˜μ˜ 별칭과 λ³€μˆ˜λ₯Ό λͺ¨λ‘ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    $ (ls -l)
    -rw-r--r-- 1 smith smith 325 Oct 13 22:19 animals.txt
    $ (alias)
    alias gd='pushd' alias l='ls -CF' alias pd='popd'
    $ (l)
    animals.txt

μ„œλΈŒ μ‰˜ μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” 방법은 BASH_SUBSHELL λ³€μˆ˜λ₯Ό 좜λ ₯ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 값이 0이 μ•„λ‹Œ 경우 μ„œλΈŒ μ‰˜μž…λ‹ˆλ‹€. BASH_SUBSHELL 값이 0이 μ•„λ‹Œ 경우(μ—¬κΈ°μ„œλŠ” 1) μ„œλΈŒ μ‰˜μž„μ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

$ echo $BASH_SUBSHELL
0
$ bash
$ echo $BASH_SUBSHELL
0
$ exit
$ (echo $BASH_SUBSHELL)
1

Coprocesses

Coprocesses are a form of parallel execution, allowing a script to execute commands in the background and communicate with them via named pipes.

coproc { sleep 2; echo "Hello from a coprocess!"; }
read -r line <&"${COPROC[0]}"
echo "Received: $line"

GNU Parallel

GNU Parallel allows executing commands in parallel, making use of multiple CPU cores to speed up execution.

$ parallel 'echo {}' ::: 1 2 3 4

Shell Functions

Functions, once defined, act like commands that can be called with or without arguments.

# Functions are declared using this syntax:
fname () compound-command [ redirections ]
function fname [()] compound-command [ redirections ]
greet() {
  echo "Hello, $1!"
}

greet "World"

Shell Parameters

Positional Parameters

Positional Parameters are numbered variables that store command line arguments, represented by $n, where n is the position of the arguments.

#!/bin/bash
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"

# Input: ./script.sh apple banana cherry
# Output:
# First argument: apple
# Second argument: banana
# Third argument: cherry

Special Parameters

Special Parameters are special characters used to represent specific shell values or elements.

$*: All positional parameters, represented as a single string
$@: All positional parameters, represented as separate strings
$#: Number of arguments passed
$$: Process ID of the current shell
$!: Process ID of the last command executed
$?: Exit status of the last command executed

Shell Expansions

Shell Expansions are transformations applied to shell commands and allow complex operations in the command line.

Brace Expansion

Brace Expansion generates multiple text strings by iterating over the provided values.

mkdir test_{01..03} 
# Creates test_01, test_02, test_03.

Tilde Expansion

Tilde Expansion substitutes the tilde (~) with the value of the home directory.

cd ~/Downloads 
# Navigates to the user's Downloads folder.

Shell Parameter Expansion

Shell Parameter Expansion substitutes parameter values with their equivalent values.

${parameter:-word}: If parameter is unset or null, this expansion returns the value of word. Otherwise, it returns the value of parameter.

VAR=
DEFAULT="hello"
echo ${VAR:-$DEFAULT}  # Output: hello
VAR="world"
echo ${VAR:-$DEFAULT}  # Output: world

${parameter-word}: If parameter is unset, this expansion returns the value of word. Otherwise, it returns the value of parameter.

VAR=
DEFAULT="hello"
echo ${VAR-$DEFAULT}  # Output:
VAR="world"
echo ${VAR-$DEFAULT}  # Output: world

${parameter:=word}: If parameter is unset or null, this expansion assigns the value of word to parameter and returns the value.

VAR=
DEFAULT="hello"
echo ${VAR:=$DEFAULT}  # Output: hello
echo $VAR              # Output: hello

${parameter:+word}: If parameter is set, then this expansion returns the value of word. Otherwise, it returns an empty string.

VAR="world"
SUFFIX="!"
echo ${VAR:+$SUFFIX}   # Output: !
VAR=
echo ${VAR:+$SUFFIX}   # Output: (empty)

${#parameter}: Returns the length of the string value of parameter.

VAR="hello"
echo ${#VAR}           # Output: 5

${parameter%pattern}: Removes the shortest suffix matching pattern from the value of parameter.

FILENAME="file.txt"
echo ${FILENAME%.*}    # Output: file

${parameter%%pattern}: Removes the longest suffix matching pattern from the value of parameter.

FILENAME="file.tar.gz"
echo ${FILENAME%%.*}   # Output: file

${parameter#pattern}: Removes the shortest prefix matching pattern from the value of parameter.

PATH="/usr/local/bin"
echo ${PATH#*/}        # Output: usr/local/bin

${parameter##pattern}: Removes the longest prefix matching pattern from the value of parameter.

PATH="/usr/local/bin"
echo ${PATH##*/}       # Output: bin

${parameter/pattern/string}: Replaces the first occurrence of pattern with string in the value of parameter.

VAR="hello world"
echo ${VAR/world/universe}  # Output: hello universe

${parameter//pattern/string}: Replaces all occurrences of pattern with string in the value of parameter.

VAR="hello world world"
echo ${VAR//world/universe}  # Output: hello universe universe

Command Substitution

Command Substitution substitutes the output of a command into its enclosing command. $()

# This will print "Today is" followed by the current date.
echo "Today is $(date)" 

Arithmetic Expansion

Arithmetic Expansion substitutes an arithmetic expression with its result.

This will output 10.
echo $((5 + 5)) 

Process Substitution

Process Substitution runs a command in a subshell and provides its input/output as a file.

# This compares the files with their sorted versions.
diff <(sort file1.txt) <(sort file2.txt) 

Word Splitting

IFS (Internal Field Separator) is an environment variable in Unix-like systems that specifies a delimiter used by the shell for word splitting and to split the results of variable expansions and command substitutions into separate fields.

Word splitting is the process by which the shell takes the results of expansions, like parameter expansions and command substitutions, and splits them into "words" or separate arguments based on the characters present in the IFS variable.

By default, IFS is set to a space, tab, and newline (' \t\n'). This means that if any of these characters are present in the result of an expansion, the shell will split the result into separate words or arguments.

#!/bin/bash
STRING="This is a test"

# Default IFS behavior:
echo "With default IFS:"
for word in $STRING; do
  echo "Word: $word"
done
# Output:
# With default IFS:
# Word: This
# Word: is
# Word: a
# Word: test

# Changing the IFS:
IFS='i'

echo "With modified IFS:"
for word in $STRING; do
  echo "Word: $word"
done
# Output:
# With modified IFS:
# Word: Th
# Word: s
# Word: s a test

Filename Expansion

Filename Expansion or globbing matches filenames using wildcards.

Pattern Matching

Pattern Matching is used within Filename Expansion to match specific file types.

*.txt: Matches all .txt files.
file?.txt: Matches file1.txt, fileA.txt, etc.

Quote Removal

Quote Removal removes quotations around arguments, allowing the shell to interpret them correctly.

# This sets VAR to Hello, World! without the quotes.
VAR="Hello, World!" 

Redirections

Redirections are used to change the input/output destinations of commands in bash.

Redirecting Input

To redirect input from a file to a command, use < followed by the filename.

sort < input.txt

Redirecting Output

To redirect the output of a command to a file, use > followed by the filename.

Example:

ls > list.txt

Appending Redirected Output

To append the output of a command to a file, use >> followed by the filename.

echo "Appended line" >> file.txt

Redirecting Standard Output and Standard Error

To redirect both standard output and standard error to a file, use &> followed by the filename.

command &> output_and_errors.txt

Appending Standard Output and Standard Error

To append both standard output and standard error to a file, use &>> followed by the filename.

command &>> output_and_errors.txt

Here Documents

Here documents allow input to be provided for a command directly within the command itself.

cat << EOF
This is a line of text.
Another line of text.
EOF

Here Strings

Here strings are used to provide a string as input to a command.

tr '[:lower:]' '[:upper:]' <<< "hello world"

Duplicating File Descriptors

To duplicate a file descriptor, use >&.

# This command duplicates file descriptor 3 to standard output (file descriptor 1).
command 3>&1

Moving File Descriptors

To move a file descriptor, use <&.

# This command moves file descriptor 3 to standard output (file descriptor 1).
command 3<&1

Opening File Descriptors for Reading and Writing

To open a file descriptor for reading and writing, use <>.

exec 3<> file.txt

Executing Commands

Simple Command Expansion

Command expansion allows the output of a command to be used as an argument in another command.

echo "Today is $(date)"

Command Search and Execution

When a command is executed, bash searches for the command in built-ins, functions, and external commands in directories specified in the $PATH variable.

$ echo $PATH

Command Execution Environment

The command execution environment includes the command, arguments, environment variables, and file descriptors.

$ env | sort

Environment

The environment consists of environment variables and shell settings.

# This command exports the MY_VARIABLE environment variable with the value "my_value".
$ export MY_VARIABLE=my_value

Exit Status

Exit status is the numerical value of the result of a command's execution. A successful command exits with the status code 0, and a failed execution exits with a non-zero status code.

command
echo $?

Signals

Signals are a way to send events to running processes. Common signals include SIGHUP, SIGINT, SIGKILL, and SIGTERM.

# The above command sends a SIGTERM signal to the process 
# with the specified process_id, requesting it to terminate gracefully.
$ kill -SIGTERM process_id

Shell Scripts

A shell script is a text file containing a series of commands that are executed by the command-line interpreter, in this case, the bash shell. Shell scripts can be used for automation of tasks, creating custom functions, and simplifying repetitive actions.

# hello_world.sh
#!/bin/bash
echo "Hello, World!"

$ chmod +x hello_world.sh
$ ./hello_world.sh

Shell Builtin Commands

Shell builtin commands are commands that are built directly into the shell itself, providing various functions and constructs that can be used in scripts and interactive shells.

Bourne Shell Builtins

Bourne shell builtins are built-in commands that are carried over from the original Unix shell, the Bourne shell (sh). Examples include cd, echo, exit, printf, and test.

cd /path/to/directory
echo "Current directory: $(pwd)"

Bash Builtin Commands

Bash builtin commands are commands specifically designed for the Bash shell. They extend the functionality of the Bourne shell builtins, providing additional features and constructs. Examples include declare, mapfile, read, select, and time.

declare -i num=5
num=num+10
echo "The value of num is $num"

Modifying Shell Behavior

There are built-in commands that can be used to modify the behavior of the Bash shell.

The Set Builtin

set is a builtin command that can be used to set or unset options that change the shell's behavior. It can also be used to set positional parameters.

set -e
# The script will exit if any command returns a non-zero status.
mkdir non_existent_directory

The Shopt Builtin

shopt is a builtin command to set or unset various shell options. It is similar to set, but it is used for more specific shell behavior settings.

shopt -s cdspell
# The shell will attempt to correct minor spelling errors 
# in directory names when using the cd command.
cd /non/exitsent/diractory

Special Builtins

Special builtins are a set of built-in commands defined by the POSIX standard. They are similar to other built-ins, but their exit status and variables located outside any function or script in which they are called can be affected by these commands. Examples include break, return, shift, and unset.

for i in {1..5}; do
  if [ "$i" == "3" ]; then
    break
  fi
  echo "Number: $i"
done

# Output:
# Number: 1
# Number: 2

Shell Variables

Shell variables are used to store information in a shell script or command-line session. They can be used for various purposes, such as storing values, referring to file paths, or configuring shell options.

Bourne Shell Variables

These are variables specific to the Bourne shell (sh). These variables are generally available in Bash as well, for compatibility reasons.

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
export PATH

Bash Variables

These are variables specific to the Bash shell. They can provide various functionalities or information to the script.

PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

Bash Features

Bash has various features that enhance its capabilities as a shell.

Invoking Bash

Invoking Bash involves starting a new instance of the shell, which can execute scripts or commands interactively.

bash script.sh

Bash Startup Files

These files are executed when a new Bash session starts. Common startup files are ~/.bash_profile, ~/.bashrc, and /etc/profile.

# ~/.bashrc
alias ll='ls -lah'

Interactive Shells

An interactive shell is a shell that allows interaction with the user, usually by typing commands.

What is an Interactive Shell?

An interactive shell allows you to run commands and see their output immediately.

$ echo "Hello, World!"
Hello, World!

Is this Shell Interactive?

To check if the current shell is interactive, you can test the value of the special variable $-.

# If the output contains the letter i, then it is an interactive shell.
$ echo $-
himBH

Interactive Shell Behavior

Interactive shells provide features like command history, tab completion, and aliases.

$ history
1 ls
2 cd ..

Bash Conditional Expressions

Conditional expressions are used in bash to decide the execution flow of a script or command.

if [ "$USER" = "root" ]; then
  echo "You are root."
else
  echo "You are not root."
fi

Shell Arithmetic

Bash supports arithmetic operations using $(()) or $[].

$ echo $((5 * 3))
15

Aliases

Aliases are shorthand commands that are created by mapping a string to a command.

$ alias ll='ls -la'
$ alias ll
$ type ll

Arrays

Arrays are variables that hold multiple values in Bash.

$ fruits=("apple" "banana" "cherry")

$ echo ${fruits[0]} 
# Output: apple

$ echo ${fruits[@]} 
# Output: apple banana cherry

The Directory Stack

The directory stack is a list of directories in Bash that can be navigated using pushd, popd, and dirs.

Directory Stack Builtins

pushd, popd, and dirs are built-in commands that help manipulate and navigate the directory stack.

$ pushd /etc
$ dirs
/etc ~/mydir

Controlling the Prompt

The shell prompt can be customized using variables like PS1 and escape sequences.

PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

The Restricted Shell

A restricted shell is a shell that has limited capabilities to restrict the user's actions.

$ rbash

Bash POSIX Mode

Bash can be run in POSIX mode to be compatible with the POSIX standard for better portability.

$ bash --posix

Shell Compatibility Mode

Bash can be invoked in compatibility mode to emulate the behavior of other shells, like sh.

$ bash --sh

Job Control

Job control allows users to manage multiple processes (jobs) running concurrently.

Job Control Basics

Job control basics include placing a process in the foreground or background, stopping a process, and resuming a stopped process. You can use the following commands:

  • &: To run a process in the background.
  • CTRL+Z: To stop a currently running foreground process.
  • jobs: To view the list of currently running jobs.
  • fg JOBID: To bring a background job to the foreground.
  • bg JOBID: To continue a stopped job in the background.
$ sleep 30 &
[1] 12345
$ jobs
[1]+ Running sleep 30 &
$ fg 1

Job Control Builtins

These are built-in commands in Bash for controlling job processes:

  • bg: Resume a stopped job in the background.
  • fg: Move a background job to the foreground.
  • jobs: Display the list of currently active jobs.
  • kill: Terminate a process by its job ID or process ID.
  • wait: Wait for a background process to finish before proceeding.
$ sleep 30 &
[1] 12345
$ jobs
[1]+ Running sleep 30 &
$ kill %1
[1]+ Terminated sleep 30

Job Control Variables

These variables provide information about the job control processes in Bash:

  • $!: Process ID of the last background command.
  • $?: Exit status of the most recently executed command.
  • $$: Process ID of the current shell.
$ sleep 10 &
[1] 12345
$ echo $!
12345

Command Line Editing

Introduction to Line Editing

Line editing in bash enables users to navigate and modify the text on the command line using keyboard shortcuts. Bash uses the Readline library for this functionality.

Readline Interaction

Readline manages the user's input and provides many useful shortcuts. There are two modes: Emacs (default) and vi mode, both with their respective key bindings.

Readline Bare Essentials

Basic commands to navigate the command line:

  • Control + A: Move to the beginning of the line
  • Control + E: Move to the end of the line
  • Control + B: Move backward one character
  • Control + F: Move forward one character
  • Control + W: Delete previous word
  • Control + K: Delete from the current cursor position to the end of the line
  • Control + U: Delete from the current cursor position to the beginning of the line

Readline Movement Commands

  • Alt + B: Move backward one word
  • Alt + F: Move forward one word
  • Control + XX: Toggle between current and previous cursor positions

Readline Killing Commands

Killing refers to cutting text, which can later be pasted (yanked) elsewhere.

  • Control + K: Kill from cursor position to end of line
  • Control + U: Kill from cursor position to beginning of line
  • Alt + D: Kill from cursor position to end of current word
  • Alt + Backspace: Kill from cursor position to beginning of current word

Readline Arguments

Some commands accept numeric arguments for more precise control. You can input a numeric argument by pressing Alt (or Escape) and then typing the number.

  • Alt + 3 Control + B: Move backward three characters
  • Alt + 3 Control + K: Kill the next three characters

Searching for Commands in the History

  • Control + R: Search for a previously executed command by typing its partial string

Readline Init File

The readline init file (~/.inputrc or /etc/inputrc) provides custom configurations for readline keybindings and settings.

Readline Init File Syntax

The syntax includes:

  • Set and unset commands for options (e.g., set enable-meta on)
  • Keybinding commands (e.g., "\C-x\C-r": re-read-init-file for Control + X, Control + R to reload the init file)

Conditional Init Constructs

Conditional constructs allow you to specify different settings for different programs or terminal types.

$if Bash
$endif

Sample Init File

# ~/.inputrc
set enable-meta on
set bell-style visible
\C-x\C-r: re-read-init-file
$if Bash
  "\C-x\C-e": edit-and-execute-command
$endif

Bindable Readline Commands

Bash and the Readline library provide many commands that can be bound to keys for customizing your workflow. The full list can be found in the Bash Reference Manual.

Commands For Moving

Commands For Manipulating The History

Commands For Changing Text

Killing And Yanking

Specifying Numeric Arguments

Letting Readline Type For You

Keyboard Macros

Some Miscellaneous Commands

Readline vi Mode

By default, Readline uses Emacs mode, but you can enable vi mode by putting set editing-mode vi in your inputrc or entering set -o vi in the command line. In vi mode, you can use vi keybindings to navigate and edit the command line.

Programmable Completion

Bash provides powerful, programmable completion features. You can customize the behavior of the Tab key to complete command names, file names, and other arguments depending on the context.

Programmable Completion Builtins

  • complete: Specify completion behavior for a specific command
  • compgen: Generate completion matches
  • compopt: Modify completion options for a specific command

A Programmable Completion Example

A simple example to autocomplete filenames with a custom command (mycat):

_my_catz() {
  local cur
  COMPREPLY=()
  cur=${COMP_WORDS[COMP_CWORD]}
  COMPREPLY=( $(compgen -f -- $cur) )
  return 0
}
complete -F _my_catz mycat

Save this script in a file (e.g., completion_example.sh) and source it in your ~/.bashrc file (source /path/to/completion_example.sh).

Using History Interactively

Bash History Facilities

Bash history is a powerful tool that keeps track of commands you've executed in the terminal. This feature provides the ability to work with previous commands. You can configure the command history with variables such as HISTSIZE (the number of commands to remember) and HISTFILESIZE (maximum number of lines in the history file). You can navigate through command history using arrow keys or search it by pressing Ctrl+R.

# Set HISTSIZE to remember the last 1000 commands
HISTSIZE=1000

Bash History Builtins

Bash provides built-in commands to interact with the command history:

  • history: Displays the command history.
  • fc: Lists, edits, or re-executes commands previously entered.
  • !: Re-executes a previous command by its number or partial string.
# Display last 10 commands:
history 10

History Expansion

Event Designators

  • !: Start a history substitution.
  • !n: Refer to command line n.
  • !-n: Refer to the command n lines back.
  • !!: Refer to the previous command.

Word Designators

Word designators allow selecting specific words from the event. Some common designators are:

  • 0: Zeroth word (usually represents the command).
  • n: The nth word.
  • $: The last word.
  • %: The word matched by the most recent !?string? search.
# Re-execute the second argument of the last command:
!$ !^

Modifiers

Modifiers alter the events or word designators. Some common modifiers are:

  • h: Remove a file name leaving only the head.
  • t: Remove all but the tail (file name).
  • r: Remove suffix (excluding the dot).
# Re-run the last executed ls command, 
# removing the file extension from files:
!!:r

Installing Bash

Basic Installation

To install Bash, you need to download the source code, extract it, and then complete the following steps:

  • cd to the directory containing the source code.
  • Run ./configure.
  • Run make.
  • Optionally, run make tests.
  • Run make install.
tar -xvf bash-x.y.tar.gz
cd bash-x.y
./configure
make
make tests
make install

Compilers and Options

Some variables are used to specify different compilers and compiler options:

  • CC: The C compiler.
  • CFLAGS: Options for the C compiler.
  • LDFLAGS: Options used when linking.
  • CPPFLAGS: Options used when running the C preprocessor.
./configure CC=gcc-9 CFLAGS="-O2 -march=native" LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include"

Compiling For Multiple Architectures

To compile Bash for multiple architectures, create a build directory for each architecture, run configure from the specific architecture directory, and use the --host and --build options to specify target and build platforms.

mkdir build-x86_64
cd build-x86_64
../configure --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu
make

Installation Names

You can use the --program-prefix, --program-suffix, and --program-transform-name options when running configure to customize the installation names.

./configure --program-prefix=my_ --program-suffix=_v1

Specifying the System Type

Configure tries to guess the correct system type, but you can also use the --build, --host, and --target options to specify the system type.

./configure --build=i686-pc-linux-gnu --host=arm-linux-gnueabihf

Sharing Defaults

The file config.site in the share subdirectory of the local directory can be used to set site-wide defaults.

./configure --prefix=/usr/local --with-config-file=config.site

Operation Controls

Some operation control options for configure includes:

  • --cache-file=FILE: Save and use results of previous tests.
  • --srcdir=DIR: Find the source code in DIR.
  • --quiet: Do not print any messages.
./configure --cache-file=config.cache --srcdir=../bash-x.y --quiet

Optional Features

Some optional features can be enabled or disabled using configure options, like --enable-debug, --enable-readline, and --enable-mem-scramble.

./configure --enable-debug --disable-readline

Job Control Advanced

Job Control

Job Id and Job specification

$ wget http://a.b.com/a.txt &
[3] 1999

Job 은 Process λ“€μ˜ λͺ¨μŒ 즉 Process Group 을 ν‘œν˜„ν•œλ‹€. job id λŠ” 3 이고 process id λŠ” 1999 이닀. job 에 signal 을 보내고 μ‹Άλ‹€λ©΄ job spec %3 을 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

$ kill -9 %3

Session and Job

λ‹€μŒκ³Ό 같이 command line 을 μ‹€ν–‰ν•΄ 보자.

$ cat
hello
hello
^Z
[1]+  Stopped       cat
$ ls | sort

λ‹€μŒμ€ session, job, process λ“€μ˜ μƒνƒœλ₯Ό 그림으둜 ν‘œν˜„ν•œ 것이닀. The TTY demystified μ°Έκ³ 

λ‹€μŒμ€ tty driver (/dev/pts/0) 의 μƒνƒœμ΄λ‹€.

Size: 45x13
Controlling process group: (101)
Foreground process group: (103)
UART configuration (ignored, since this is an xterm):
  Baud rate, parity, word length and much more.
Line discipline configuration:
  cooked/raw mode, linefeed correction,
  meaning of interrupt characters etc.
Line discipline state:
  edit buffer (currently empty),
  cursor position within buffer etc.

λ‹€μŒμ€ pipe0 의 μƒνƒœμ΄λ‹€.

Readable end (connected to PID 104 as file descriptor 0)
Writable end (connected to PID 103 as file descriptor 1)
Buffer

Jobspec vs Pid

pid λŠ” νŠΉμ • ν”„λ‘œμ„ΈμŠ€λ₯Ό μ˜λ―Έν•˜μ§€λ§Œ job spec 은 νŒŒμ΄ν”„λ‘œ μ—°κ²°λœ λͺ¨λ“  ν”„λ‘œμ„ΈμŠ€λ₯Ό μ˜λ―Έν•œλ‹€.

$ sleep 100 | sleep 100 | sleep 100 &
[1] 65
$ jobs %1
[1]+  Running                 sleep 100 | sleep 100 | sleep 100 &
$ ps axjf
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0    15    15    15 pts/1       66 Ss       0   0:00 /bin/bash
   15    63    63    15 pts/1       66 S        0   0:00  \_ sleep 100
   15    64    63    15 pts/1       66 S        0   0:00  \_ sleep 100
   15    65    63    15 pts/1       66 S        0   0:00  \_ sleep 100
   15    66    66    15 pts/1       66 R+       0   0:00  \_ ps axjf
    0     1     1     1 pts/0        1 Ss+      0   0:00 /bin/bash

Job Control Builtins

  • jobs
    • jobs ν˜„μž¬ job table λͺ©λ‘μ„ 보여쀀닀.
    • jobs -l show job table with process id
    • %+ job spec which means current job
    • %- job spec which means previous job
    • jobs -p show just process id which is representative.
  • fg [jobspec]
    • make it foreground job.
  • bg [jobspec ...]
    • make it background job.
  • suspend
    • stop until get the SIGCONT signal.
    • suspend -f login shell μ—μ„œ μ‚¬μš©ν•  수 μ—†μ§€λ§Œ oevrride κ°€ κ°€λŠ₯ν•˜λ‹€.
  • disown [-h] [-ar] [jobspec ...]
    • do not make it stop. just remove from job table.
    • shopt -s huponexit κ°€ μ„€μ •λ˜μ–΄ μžˆλŠ” 경우 login shell μ—μ„œ exit ν•  λ•Œ SIGHUP μ‹œκ·Έλ„μ— μ˜ν•΄ job μ’…λ£Œλ˜λŠ” 것을 막을 수 μžˆλ‹€.
    • -h μ˜΅μ…˜λ„ λ™μΌν•œ 역할을 ν•˜μ§€λ§Œ job 이 job table 에 λ‚¨μ•„μžˆκΈ° λ•Œλ¬Έμ— control ν•  수 μžˆλ‹€.
  • wait
    • wait [-n] [jobspec or pid ...]
    • background job 이 μ’…λ£Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦°λ‹€. child ν”„λ‘œμ„ΈμŠ€λ§Œ wait ν•  수 μžˆλ‹€.

Job Control Keys

  • Ctrl c
    • send the SIGINT signal to foreground job.
  • Ctrl z
    • send the SIGTSTP signal (suspend) to foreground job and make the background job the foreground job.

Input and Output

  • Input
    • μž…λ ₯은 foreground job μ—μ„œλ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€. background job μ—μ„œ μž…λ ₯을 λ°›κ²Œλ˜λ©΄ SIGTTIN μ‹ ν˜Έκ°€ μ „λ‹¬λ˜μ–΄ suspend λœλ‹€.
  • Output
    • 좜λ ₯은 ν˜„μž¬ session μ—μ„œ μ‹€ν–‰λ˜κ³  μžˆλŠ” λͺ¨λ“  job 듀이 κ³΅μœ ν•œλ‹€. stty tostop 을 μ‚¬μš©ν•˜λ©΄ background job μ—μ„œ 좜λ ₯이 λ°œμƒν–ˆμ„ λ•Œ suspend μ‹œν‚¬ 수 μžˆλ‹€.

Background job 은 subshell μ—μ„œ μ‹€ν–‰λœλ‹€.

$ AA=100; echo $$ $BASHPID;
15 15
$ { AA=200; echo $$ $BASHPID; } &
[1] 70
$ 15 70

[1]+  Done                    { AA=200; echo $$ $BASHPID; }
$ echo $AA
100

Script 파일 μ‹€ν–‰ 쀑에 background 둜 μ‹€ν–‰

슀크립트 νŒŒμΌμ„ μ‹€ν–‰ 도쀑에 background 둜 λͺ…령을 μ‹€ν–‰ν•˜λ©΄ μ‹€ν–‰λ˜λŠ” λͺ…령은 job table 에 λ‚˜νƒ€λ‚˜μ§€ μ•Šκ³  stdin 은 /dev/null 에 μ—°κ²°λœλ‹€. parent process 에 ν•΄λ‹Ήν•˜λŠ” 슀크립트 파일이 λ©΄μ € μ’…λ£Œν•˜λ©΄ PPID κ°€ init 으둜 λ°”λ€Œμ–΄ 싀행을 κ³„μ†ν•˜λ―€λ‘œ daemon 으둜 λ§Œλ“€ 수 μžˆλ‹€.

Shell 이 μ’…λ£Œλ˜λ©΄ background job 은 μ–΄λ–»κ²Œ λ˜λŠ”κ°€?

  • prompt μ—μ„œ exit λ‚˜ logout 으둜 μ’…λ£Œν•˜λŠ” 경우
    • background job 이 stopped 인 경우
      • prompt 에 job 이 μ’…λ£Œλ˜μ—ˆλ‹€κ³  μ•Œλ €μ€€λ‹€.
    • background job 이 running 인 경우
      • ppid κ°€ init 으둜 바뀐닀.
      • login shell 인 경우 shopt -s huponexit κ°€ μ„€μ •λ˜μ—ˆλ‹€λ©΄ logout ν–ˆμ„ λ•Œ λͺ¨λ“  running background job 듀이 SIGHUP 을 μˆ˜μ‹ ν•˜κ³  μ’…λ£Œν•œλ‹€.
  • μœˆλ„μš°μ—μ„œ terminal program 을 μ’…λ£Œν•˜κ±°λ‚˜ μ‹œμŠ€ν…œμ΄ μ’…λ£Œλ˜λŠ” 경우
    • remote login μ—μ„œ λ„€νŠΈμ›, λͺ¨λŽ€ 연결이 λŠκΈ°κ±°λ‚˜ interactive shell 에 kill -HUP μ‹ ν˜Έλ₯Ό μ£ΌλŠ” κ²½μš°λ„ ν•΄λ‹Ήν•œλ‹€.
    • shell 의 stopped, running job 듀이 λͺ¨λ‘ SIGHUP 을 λ°›κ³  μ’…λ£Œν•œλ‹€.

Session and Process Group

터미널을 μ—΄λ©΄ shell 이 μ‹€ν–‰λœλ‹€. shell pid λŠ” sid (session id) μ΄λ©΄μ„œ session leader 이닀. 이후 μžμ† process 듀은 λͺ¨λ‘ 같은 sid λ₯Ό κ°–λŠ”λ‹€. shell script κ°€ μ‹€ν–‰λ˜λ©΄ process group 이 λ§Œλ“€μ–΄μ§„λ‹€. script pid κ°€ pgid (process group id) κ°€ 되며 process group leader κ°€ λœλ‹€. μƒˆλ‘œ μƒμ„±λ˜λŠ” ν”„λ‘œμ„ΈμŠ€λŠ” parent process 의 pgid λ₯Ό μƒμ†ν•œλ‹€. λ”°λΌμ„œ 이후 script μ—μ„œ μ‹€ν–‰λ˜λŠ” process 듀은 λͺ¨λ‘ 같은 pid λ₯Ό κ°–λŠ”λ‹€.

| λ₯Ό 톡해 μ—¬λŸ¬ λͺ…령을 μ‹€ν–‰ν•˜λŠ” κ²½μš°λ„ process group 이 λ§Œλ“€μ–΄μ§„λ‹€. μ΄λ•Œ 첫번째 λͺ…λ Ήμ˜ pid κ°€ pgid, process group leader κ°€ λœλ‹€.

μ‘°νšŒν•˜κ³  μ‹ ν˜Έλ³΄λ‚΄κΈ°

$ ps jf
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    0    15    15    15 pts/1       83 Ss       0   0:00 /bin/bash
   15    83    83    15 pts/1       83 R+       0   0:00  \_ ps jf
    0     1     1     1 pts/0        1 Ss+      0   0:00 /bin/bash

$ ps fo user,ppid,pid,pgid,sid,comm
USER      PPID   PID  PGID   SID COMMAND
root         0    15    15    15 bash
root        15    84    84    15  \_ ps
root         0     1     1     1 bash

싀행쀑인 슀크립트λ₯Ό μ’…λ£Œν•˜λŠ” 방법

script λ₯Ό μ’…λ£Œν•˜κ³  μ‹Άλ‹€λ©΄ jobspec ν˜Ήμ€ pgid λ₯Ό μ΄μš©ν•˜μ—¬ process group 에 signal 을 보낸닀. Ctrl c λŠ” process group 에 signal 을 λ³΄λ‚΄λŠ” 방법이닀.

μƒˆλ‘œμš΄ sid 둜 μ‹€ν–‰ν•˜κΈ°

script λ₯Ό background 둜 μ‹€ν–‰ν•  λ•Œ setsid λ₯Ό μ΄μš©ν•˜λ©΄ μƒˆλ‘œμš΄ sid, pgid κ°€ ν• λ‹Ήλ˜κ³  ppid 도 init 으둜 바뀐닀. sid κ°€ λ°”λ€ŒκΈ° λ•Œλ¬Έμ— controlling terminal μ—μ„œ λΆ„λ¦¬λ˜κ³  /dev/tty 도 μ‚¬μš©ν•˜μ§€ λͺ»ν•œλ‹€. ppid κ°€ init 이 되기 λ•Œλ¬Έμ— script λ₯Ό daemon 으둜 λ§Œλ“€ 수 μžˆλ‹€.

$ setsid a.sh > /dev/null 2>&1 < /dev/null

pgid λ₯Ό λ³€κ²½ν•˜μ—¬ child process λ₯Ό μ‹€ν–‰

script λ₯Ό a.sh -> b.sh -> c.sh -> d.sh μˆœμ„œλ‘œ d.sh μ—μ„œ sleep μƒνƒœμ— μžˆλ‹€κ³  ν•˜μž. Ctrl c λ₯Ό λˆ„λ₯Ό 경우 tty driver 에 μ˜ν•΄ SIGINT μ‹ ν˜Έκ°€ foreground process group 에 μ „λ‹¬λ˜μ–΄ 4 개의 ν”„λ‘œμ„ΈμŠ€λŠ” λͺ¨λ‘ μ’…λ£Œν•œλ‹€. λ§Œμ•½, b.sh μ—μ„œ c.sh λ₯Ό μ‹€ν–‰ν•  λ•Œ pgid λ₯Ό λ³€κ²½ν•˜λ©΄ c.sh, d.sh 만 μ’…λ£Œν•˜κ³  a.sh, b.sh λŠ” μ‹€ν–‰λ˜κ²Œ ν•  수 μžˆλ‹€.

shell μ—μ„œ setsid λ₯Ό μ‚¬μš©ν•˜μ—¬ sid, pgid λ₯Ό λ³€κ²½ν•  수 μžˆμ§€λ§Œ setpgid λŠ” μ—†λ‹€. κ·ΈλŸ¬λ‚˜ set -o monitor μ˜΅μ…˜μ„ μ„€μ •ν•˜μ—¬ λ‹€λ₯Έ pgid λ₯Ό κ°–κ²Œ ν•  수 μžˆλ‹€.

  • b.sh
#!/bin/bash
..
set -o monitor
source c.sh
...

Process State Codes

$ ps ax

symbol description
D uninterruptible sleep (usually IO)
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped, either by a job control signal or because it is being traced.
t stopped by debugger during the tracing
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent.

additional information with BSD format

symbol description
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
` `
+ is in the foreground process group.

TTY

tty λŠ” TeleTYpewriterλ₯Ό μ˜λ―Έν•œλ‹€. 터미널을 μ˜λ―Έν•˜λŠ” 단어이닀. 1869 λ…„ νƒ€μžκΈ°μ™€ λΉ„μŠ·ν•˜κ²Œ 생긴 Teletype Writer λΌλŠ” μž₯μΉ˜κ°€ μžˆμ—ˆλ‹€. μΌμ’…μ˜ 터미널이닀. telex λΌλŠ” network 에 μ—°κ²°λ˜μ–΄ μžˆμ—ˆλ‹€κ³  ν•œλ‹€. 1970 λ…„λŒ€μ— λΉ„λ””μ˜€ μž₯μΉ˜κ°€ 달린 VT-100 μ΄λΌλŠ” 터미널이 κ°œλ°œλ˜μ—ˆλ‹€. μ§€κΈˆμ€ physical teletype ν˜Ήμ€ video terminal 을 μ‚¬μš©ν•˜μ§€ μ•Šμ§€λ§Œ linux kernel μ•ˆμ— κ·Έ κ°œλ…λ“€μ΄ μˆ¨μ–΄μžˆλ‹€.

μž…μΆœλ ₯ μž₯치 μ‚¬μš©μ˜ ꡬ뢄

μ™ΈλΆ€ 터미널 μž₯치 μ—°κ²°

VT100 κ³Ό 같은 μ™ΈλΆ€ 터미널 μž₯μΉ˜κ°€ μ‹œλ¦¬μ–Ό 라인을 톡해 μ—°κ²°λ˜λŠ” κ²½μš°μ΄λ‹€. getty process κ°€ background μ—μ„œ line 을 λͺ¨λ‹ˆν„°λ§ν•˜κ³  μžˆλ‹€κ°€ 터미널 접속을 λ°œκ²¬ν•˜λ©΄ login prompt λ₯Ό 보여쀀닀. /dev/ttyS[number] 파일이 μ‚¬μš©λœλ‹€. UART driver λŠ” bytes λ₯Ό μ „μ†‘ν•˜κ³  parity check ν˜Ήμ€ flow control 을 μˆ˜ν–‰ν•œλ‹€. Line discipline λΌλŠ” layer λ₯Ό λ‘μ–΄μ„œ UART driver λ₯Ό μ—¬λŸ¬ λ‹€λ₯Έ μž₯치둜 μ‚¬μš©ν•  수 μžˆλ‹€. baskspace, erase word, clear line, reprint 같은 line editing κΈ°λŠ₯을 standard line discipline 을 톡해 μ œκ³΅ν•œλ‹€.

TTY driver λŠ” session management 즉 job control κΈ°λŠ₯을 ν•œλ‹€. Ctrl z λ₯Ό λˆ„λ₯΄λ©΄ running job 을 suspend μ‹œν‚€κ³  user input 은 foreground job μ—λ§Œ μ „λ‹¬ν•œλ‹€. background job 이 μž…λ ₯을 λ°›μœΌλ©΄ SIGTTIN μ‹ ν˜Έλ₯Ό 보내 suspend μ‹œν‚¨λ‹€.

Linux Virtual Console

OS μ—μ„œ μ œκ³΅ν•˜λŠ” virtual console 이닀. Ctrl - Alt - F1 ~ F6 으둜 μ „ν™˜ν•œλ‹€. kernal μ—μ„œ terminal 을 emulation ν•œλ‹€. μ™ΈλΆ€ 터미널 μž₯치 μ—°κ²° κ³Ό λΉ„κ΅ν•΄μ„œ μ΄ν•΄ν•˜μž. /dev/tty[num] νŒŒμΌμ„ μ‚¬μš©ν•œλ‹€. Line discipline, TTY driver 의 κΈ°λŠ₯은 μœ„μ™€κ°™κ³  μ—­μ‹œ λ°±κ·ΈλΌμš΄λ“œ getty ν”„λ‘œμ„ΈμŠ€μ—μ˜ν•΄ login prompt κ°€ μ œκ³΅λœλ‹€. /dev/tty[번호] 파일이 μ‚¬μš©λœλ‹€.

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

μ•žμ„œ μ–ΈκΈ‰ν•œ Linux Virtual Console μ—μ„œλŠ” μ»€λ„μ—μ„œ 터미널을 emulation ν–ˆλ‹€λ©΄, TTY driver κ°€ μ œκ³΅ν•˜λŠ” session management κΈ°λŠ₯κ³Ό Line Discipline 을 κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©΄μ„œ μ‚¬μš©μž ν”„λ‘œκ·Έλž¨μ—μ„œ 터미널을 emulation ν•˜λŠ”κ²ƒμ΄ PTY (Pseudo TTY) μž…λ‹ˆλ‹€.

PTY λŠ” master/slave 둜 이루어 진닀. /dev/ptmx νŒŒμΌμ„ open ν•˜λ©΄ pseudo terminal master 에 ν•΄λ‹Ήν•˜λŠ” file descriptor κ°€ μƒμ„±λ˜κ³  pseudo terminal slave (PTS) 에 ν•΄λ‹Ήν•˜λŠ” device κ°€ /dev/pts/ 디렉토리에 μƒμ„±λœλ‹€. ptm κ³Ό pts κ°€ open 되면 /dev/pts/[번호] λŠ” μ‹€μ œ 터미널과 같은 μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν”„λ‘œμ„ΈμŠ€μ— μ œκ³΅ν•©λ‹ˆλ‹€.

ptm 에 write ν•œ data λŠ” pts 의 input 으둜 pts 에 write ν•œ data λŠ” ptm 의 input 으둜 μ‚¬μš©λœλ‹€. kernel 이 μ²˜λ¦¬ν•˜λŠ” layer κ°€ 쀑간에 λ“€μ–΄κ°„ named pipe 와 λΉ„μŠ·ν•˜λ‹€.

xterm 을 μ‹€ν–‰ν•˜κ±°λ‚˜ μ™ΈλΆ€μ—μ„œ ssh client κ°€ μ ‘μ†ν•˜λ©΄ /dev/pts/ 에 device 파일이 μƒˆλ‘œ μƒμ„±λœλ‹€.

μœ„μ˜ 그림은 xterm 을 μ‹€ν–‰ν•œ 경우λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. xterm μ—μ„œ ls λ₯Ό μž…λ ₯ν•˜λ©΄ ptm -> line discipline -> pts λ₯Ό κ±°μ³μ„œ bash shell (user process) 에 μ „λ‹¬λ˜κ³  ls 의 κ²°κ³Όκ°€ pts -> line discipline -> ptm 을 ν†΅ν•΄μ„œ xterm 에 μ „λ‹¬λ˜λ©΄ xterm 은 terminal κ³Ό 같이 화면에 ν‘œμ‹œν•œλ‹€.

μœ„μ˜ 그림은 telnet 을 μ‹€ν–‰ν•˜μ—¬ Server 의 telnetd 에 μ ‘μ†ν•œ 경우λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. ν„°λ―Έλ„μ—μ„œ ls λͺ…령을 μ‹€ν–‰ν•˜λ©΄ telnet λͺ…λ Ήμ˜ μž…λ ₯으둜 λ“€μ–΄κ°€κ³  λ„€νŠΈμ›μ„ 거쳐 telnetd 에 μ „λ‹¬λ˜λ©΄ ptm, pts λ₯Ό 거쳐 bash ν”„λ‘œμ„ΈμŠ€μ— μ „λ‹¬λœλ‹€. λͺ…λ Ήμ˜ μ‹€ν–‰κ²°κ³ΌλŠ” λ‹€μ‹œ pts, ptm 을 κ±°μ³μ„œ telnetd 에 μ „λ‹¬λ˜κ³  λ„€νŠΈμ›μ„ 거쳐 telnet λͺ…령에 μ „λ‹¬λ˜λ©΄ ν„°λ―Έλ„λ‘œ 좜λ ₯ν•˜κ²Œ λœλ‹€.

μœ„μ˜ 그림은 ssh λ₯Ό μ‹€ν–‰ν•˜μ—¬ Server 의 sshd 에 μ ‘μ†ν•œ 경우λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. Console & TTY Driver μ°Έκ³ 

Controlling Terminal

Controlling Terminal 은 session leader 에 μ˜ν•΄ ν• λ‹Ήλ˜λ©° 보톡 /dev/tty* ν˜Ήμ€ /dev/pts/* 와 같은 terminal device λ₯Ό μ˜λ―Έν•œλ‹€.

PID 와 SID κ°€ 같은 ν”„λ‘œμ„ΈμŠ€λ₯Ό session leader 라고 ν•œλ‹€. session leader 만이 controlling terminal 을 νšλ“ν•  수 μžˆλ‹€. session leader λ₯Ό controlling process 라고도 ν•œλ‹€. ν•˜λ‚˜μ˜ session 은 ν•˜λ‚˜μ˜ controlling terminal 만 κ°€μ§ˆ 수 μžˆλ‹€.

μ„Έμ…˜μ€ ν•˜λ‚˜μ˜ foreground process group κ³Ό μ—¬λŸ¬κ°œμ˜ background process groups 둜 κ΅¬μ„±λœλ‹€. Ctrl-c λ₯Ό λˆ„λ₯΄λ©΄ SIGINT μ‹ ν˜Έκ°€ foreground process group 에 μ „λ‹¬λœλ‹€. modem (or network) 연결이 끊기면 SIGHUP μ‹ ν˜Έκ°€ session leader 에 μ „λ‹¬λ˜κ³  session leader λŠ” 같은 SID λ₯Ό κ°–λŠ” ν”„λ‘œμ„ΈμŠ€λ“€μ—κ²Œ μ „λ‹¬ν•œλ‹€.

$ ps x λͺ…령을 μ‹€ν–‰ν•˜μ˜€μ„λ•Œ λ‘λ²ˆμ§Έ TTY μ»¬λŸΌμ— λ‚˜μ˜€λŠ” λ‚΄μš©μ΄ controlling terminal (ctty) 이닀. ctty λ₯Ό 갖지 μ•ŠλŠ” ν”„λ‘œμ„ΈμŠ€λŠ” ? 둜 ν‘œμ‹œ λ©λ‹ˆλ‹€.

/dev/tty

/dev/tty λŠ” νŠΉμˆ˜ν•œ 파일이고 process 의 controlling terminal κ³Ό κ°™λ‹€. ν˜„μž¬ ctty κ°€ /dev/pts/12 이라면 /dev/tty 도 /dev/pts/12 와 κ°™λ‹€κ³  ν•  수 μžˆμŠ΅λ‹ˆλ‹€

Configuring TTY device

tty λͺ…λ ΉμœΌλ‘œ ν˜„μž¬ shell 의 tty device λ₯Ό μ‘°νšŒν• μˆ˜ 있고, stty λͺ…령을 μ΄μš©ν•΄ 섀정값을 λ³€κ²½ν• μˆ˜ μžˆλ‹€.

# show current tty
$ tty
/dev/pts/1

# set tty config
$ ssty -a
speed 38400 baud; rows 26; columns 190; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^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 -flusho -extproc

"-" prefix λŠ” off λ₯Ό μ˜λ―Έν•œλ‹€.

attribute description
speed UART parameters 이닀. pseudo terminal μ—μ„œλŠ” ν•„μš”μ—†λ‹€.
rows, columns terminal 의 ν–‰μ—΄μ˜ 크기이닀. 창을 λ³€ν™”ν•˜λ©΄ foreground job 에 SIGWINCH λ₯Ό 보낸닀. 그리고 값이 λ³€ν™”ν•œλ‹€.
line line discipline 값이닀. 0 은 line editing 을 μ œκ³΅ν•˜λŠ” standard line discipline 이닀.
intr = ^C foreground job 에 SIGINT λ₯Ό λ³΄λ‚΄λŠ” shortcut 이닀.
icanon line sdscipline 이닀. canonical mode λ₯Ό μ˜λ―Έν•œλ‹€. canonical mode λŠ” backspace 둜 μˆ˜μ •ν•˜κ³  enter λ₯Ό λˆ„λ₯΄λ©΄ 라인을 λ‹¨μœ„λ‘œ 데이터전솑을 ν•œλ‹€. vi λŠ” command mode κ°€ non-canonical mode 와 κ°™λ‹€.

μžμ„Έν•œ 것은 man tty λ₯Ό μ½μ–΄λ³΄μž.

Reset Command

ν”„λ‘œκ·Έλž¨μ΄ 비정상 μ’…λ£Œν•˜μ—¬ 터미널 섀정이 μ •μƒμ μœΌλ‘œ λ³΅κ΅¬λ˜μ§€ μ•Šμ•˜μ„ κ²½μš°μ—λŠ” reset command λ₯Ό μ΄μš©ν•˜μ—¬ μ΄ˆκΈ°ν™”ν•  수 μžˆλ‹€. reset λͺ…령은 λ‹€μŒκ³Ό 같은 역할을 μˆ˜ν–‰ν•œλ‹€.

  • Set Cooked and Echo modes to on
  • Turn off cbreak and Raw modes
  • Turn on new-line translation
  • Restore special characters to a sensible state.
  • Any special character that is found to be NULL or -1 is reset to its default value.

Control Keys

attribute description
^M Enter
^C Send a SIGINT to foreground job
^D End of file
^\ Send a SIGQUIT to foreground job and create core dump
^S pause screen output
^Q resume screen output
DEL or ^? erase last character
^U delete line to left
^Z send SIGTSTP to foreground job and make it suspended

End of file

read function 은 0 byte λ₯Ό 읽으면 λͺ¨λ‘ μ½μ—ˆλ‹€κ³  νŒλ‹¨ν•˜κ³  μ’…λ£Œν•œλ‹€. 0 byte κ°€ 곧 end of file 이닀. Ctrl-D κ°€ 곧 EOF λ₯Ό μ˜λ―Έν•œλ‹€.

Race condition

λ‘κ°œμ˜ ν”„λ‘œμ„ΈμŠ€κ°€ stdout, stderr 에 좜λ ₯을 μˆ˜ν–‰ν•œλ‹€λ©΄ race condition 이 λ°œμƒν•œλ‹€. λ‹€μŒμ€ f() 의 첫번째 echo κ°€ λ‘λ²ˆμ§Έ echo 와 경합을 λ²Œμ—¬μ„œ 빨간색을 좜λ ₯ν•˜λŠ” κ²½μš°μ΄λ‹€.

f() {
  { echo 111; date; echo 222; } &
  { echo -en "\e[31m"; sleep 1; echo -en "\e[m"; } >&2
}

SIGHUP Signal

terminal 이 μ—†μ–΄μ‘Œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. 터미널이 μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ λͺ…령을 μž…λ ₯ν•  μˆ˜λ„, κ²°κ³Όλ₯Ό 좜λ ₯ν•  μˆ˜λ„ μ—†λ‹€. remote login μ—μ„œ λ„·νŠΈμ›, λͺ¨λŽ€ 연결이 λŠκΈ°κ±°λ‚˜ λ˜λŠ” μ‚¬μš©μžκ°€ 터미널 ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œμ‹œν‚€λ©΄ shell 에 SIGHUP μ‹ ν˜Έκ°€ μ „λ‹¬λœλ‹€. interactive shell 이 SIGHUP 을 μˆ˜μ‹ ν•˜λ©΄ stopped, running job 듀도 SIGHUP 을 μˆ˜μ‹ ν•œλ‹€.

Mutual Exclusion

두 process κ°€ ν•˜λ‚˜μ˜ μžμ›μ„ 가지고 κ²½μŸμ„ ν•˜κ²Œ 되면 λ¬Έμ œκ°€ λ°œμƒν•œλ‹€. λ‹€μŒκ³Ό 같이 lock νŒŒμΌμ„ μ΄μš©ν•˜μ—¬ race condition 을 ν•΄κ²°ν•΄ 보자.

#!/bin/bash

lockfile=/var/lock/$(basename "$0")

if [ -f "$lockfile" ]; then                          
    exit 1
fi                        

touch "$lockfile"
trap 'rm -f "$lockfile"' EXIT
...

κ·ΈλŸ¬λ‚˜ νŒŒμΌμ„ ν™•μΈν•˜κ³  μƒμ„±ν•˜λŠ” 과정이 λΆ„λ¦¬λ˜μ–΄ μžˆλ‹€. ν•˜λ‚˜μ˜ transaction 으둜 λ¬Άμ—¬ μžˆμ§€ μ•Šλ‹€. λ‹€μŒκ³Ό 같이 mkdir 을 μ΄μš©ν•΄μ„œ ν•΄κ²°ν•΄λ³΄μž.

#!/bin/bash

lockfile=/var/lock/$(basename "$0")

if ! mkdir "$lockfile" 2> /dev/null; then 
    exit 1
fi                        

trap 'rmdir "$lockfile"' EXIT
...

λ‹€μŒμ€ set -C 을 μ΄μš©ν•˜μ—¬ ν•΄κ²°ν•œ μ˜ˆμ΄λ‹€.

#!/bin/bash

lockfile=/var/lock/$(basename "$0")
if ! (set -C; : > "$lockfile") 2> /dev/null; then
    exit 1
fi
trap 'rm -f "$lockfile"' EXIT
...

flock

flock 을 μ΄μš©ν•˜λ©΄ ν•˜λ‚˜μ˜ 블둝을 ν•˜λ‚˜μ˜ transaction 으둜 묢을 수 μžˆλ‹€.

#!/bin/bash

lockfile=$0
tasks_file=tasks.txt

read_task_id() { ... ;}
delete_task_id() { ... ;}
do_task() { ... ;}

# this is a critical section because of file descriptor 9
get_task_id ()  
{  
    flock 9     # lock with file descriptor
    local task_id
    task_id=$(read_task_id);     # 1. read task id

    if [ -n "$task_id" ]; then   # 2. if task id exists
        delete_task_id           #    delete it 
        echo "$task_id"          #    echo
    else
        echo 0                   # 3. if task id does not exist echo 0
    fi

} 9< "$lockfile"  # make a file for lock

while true; do
    task_id=$(get_task_id)
    [ "$task_id" -eq 0 ] && break
    do_task "$task_id" 
done

μœ„μ˜ get_task_id λŠ” μ•„λž˜μ™€ κ°™λ‹€.

get_task_id ()
{
    exec 9< "$lockfile"
    flock 9
    ...
} 

flock -u 9 을 μ΄μš©ν•˜μ—¬ lock 을 ν•΄μ œν•  μˆ˜λ„ μžˆλ‹€.

get_task_id_ ()
{
    flock 9
    ...
    flock -u 9
    ...
} 9< "$lockfile"  # make a file for lock

이제 μ•žμ„œ μ–ΈκΈ‰ν–ˆλ˜ mkdirλ₯Ό μ΄μš©ν•˜μ—¬ critical section 을 κ΅¬ν˜„ν•œ 것을 λ‹€μŒκ³Ό 같이 flock 을 μ΄μš©ν•˜μ—¬ κ΅¬ν˜„ν•΄ 보자. flock -n 9 은 λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€κ°€ 이미 lock 을 가지고 μžˆλŠ” 경우 λ°”λ‘œ fail return ν•œλ‹€.

#!/bin/bash

lockfile=$0

exec 9< "$lockfile"
flock -n 9 || { echo already in use; exit 1 ;}
...

flock 의 직접 λͺ…λ Ή μ‹€ν–‰

기쑴의 ν•¨μˆ˜λ₯Ό μˆ˜μ •ν•˜μ§€ μ•Šκ³  flock 으둜 critical section 을 κ΅¬ν˜„ν•΄ 보자.

$ export -f func1
$ flock /var/lock/mylock -c 'func1 11 22 33'

기쑴의 슀크립트λ₯Ό μˆ˜μ •ν•˜μ§€ μ•Šκ³  flock 으둜 critical section 을 κ΅¬ν˜„ν•΄ 보자.

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

Lock propagation

flock -o 을 μ‚¬μš©ν•˜λ©΄ server.sh κ°€ 싀행될 λ•Œ lock 을 μ†Œμœ ν•˜μ§€ μ•ŠλŠ”λ‹€.

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

Lock, lockfile

flock λŠ” λ°˜λ“œμ‹œ file descriptor κ°€ ν•„μš”ν•˜λ‹€.

# use /tmp as a lockfile
flock [option] /tmp command ...       

# use /dev/null as a lockfile
exec 9> /dev/null                    
flock 9

# use self script as a lockfile
exec 9< "$0"
flock 9

# this will make a critical section when use in the first line of the script
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER=$0 flock -n "$0" "$0" "$@" || :

Signals

Signal List

# list the signal names
$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 2) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
1)  SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
2)  SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
3)  SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
4)  SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
5)  SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
6)  SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
7)  SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
8)  SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
9)  SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
10) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
11) SIGRTMAX-1  64) SIGRTMAX

kill

λ‹€μŒμ€ kill을 μ΄μš©ν•˜μ—¬ SIGTERM을 λ³΄λ‚΄λŠ” 방법이닀.

$ kill -TERM 1111
$ kill -SIGTERM 1111
$ kill -s TERM 1111
$ kill -s SIGTERM 1111
$ kill -15 1111
$ kill -n 15 1111
$ kill 1111

- λ₯Ό μ΄μš©ν•˜λ©΄ process group 에 signal을 보낼 수 μžˆλ‹€.

$ kill -TERM -1111
$ kill -- -1111

kill -0 은 process κ°€ μ‚΄μ•„μžˆκ³  signal 을 보낼 수 μžˆλŠ”μ§€ κ²€μ‚¬ν•œλ‹€.

# 1111 ν”„λ‘œμ„ΈμŠ€λŠ” μ‘΄μž¬ν•  λ•Œ
$ kill -0 1111; echo $?
0
# 1111 ν”„λ‘œμ„ΈμŠ€λŠ” μ‘΄μž¬ν•˜μ§€ μ•Šμ„λ•Œ
$ kill -0 1111; echo $?
1
# 0 processμ—κ²Œ signal을 보낼 κΆŒν•œμ΄ μ—†λ‹€.
$ kill -9 1; echo $?
1

μžμ‹ μ˜ 그룹에 μ†ν•œ λͺ¨λ“  ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œν•΄λ³΄μž.

$ kill -TERM 0
$ kill 0
$ kill -INT 0

Trap

signal handler λ₯Ό λ“±λ‘ν•˜μž.

$ trap 'myhandler' INT
$ myhandler() { ...;}
# default handler둜 resetν•˜μž.
$ trap INT
$ trap - INT
# signal을 ignoreν•˜μž.
$ trap '' INT

SIGKILL, SIGSTOP, SIGCONTλŠ” trap 으둜 handler λ₯Ό 등둝할 수 μ—†λ‹€. default handler 만 μ‚¬μš© κ°€λŠ₯ν•˜λ‹€.

process κ°€ μ •μƒμ’…λ£Œλ  λ•Œ handler λ₯Ό λ“±λ‘ν•˜λ €λ©΄ HUP, INT, QUIT, TERM λ“±μ˜ signal 을 trap ν•΄μ•Ό ν•œλ‹€. κ·ΈλŸ¬λ‚˜ EXIT λΌλŠ” pseudo signal 을 ν•˜λ‚˜λ§Œ 등둝해도 λ™μΌν•œ κΈ°λŠ₯을 ν•œλ‹€. λ‹€μŒμ€ pseudo signal 의 λͺ©λ‘μ΄λ‹€.

Signal Description
EXIT shell 이 exit ν• λ•Œ λ°œμƒ. ( subshell 에도 적용 κ°€λŠ₯ )
ERR λͺ…령이 0 이 μ•„λ‹Œ 값을 리턴할 경우 λ°œμƒ.
DEBUG λͺ…λ Ή 싀행전에 맀번 λ°œμƒ.
RETURN ν•¨μˆ˜μ—μ„œ λ¦¬ν„΄ν• λ•Œ, source ν•œ νŒŒμΌμ—μ„œ λ¦¬ν„΄ν• λ•Œ λ°œμƒ.
$ trap 'myhandler' HUP INT QUIT TERM
$ myhandler() { ...;}

Short Cuts


  • Command Editing
shortcut action
CTRL + a move to the beginning of the line
CTRL + e move to the end of the line
CTRL + k clear the characters on the line after the current cursor position
CTRL + u clear the entire line
CTRL + w delete the word in front of the cursor
CTRL + y paste word or text that was cut using one of the deletion shortcuts after the cursor
CTRL + xx move between start of command line and current cursor position
CTRL + [left arrow], ALT-b move one word backward
CTRL + [right arrow], ALT-f move one word forward
Alt + d delete the word after the cursor
Alt + c capitalize to end of word starting at cursor
Alt + u make uppercase from cursor to end of word
Alt + l make lowercase from cursor to end of word
Alt + t swap current word with previous
CTRL + f move forward one character
CTRL + b move backward one character
CTRL + d delete character under the cursor
CTRL + h delete character before the cursor
CTRL + t swap character under cursor with the previous one
  • Command Recall
shortcut action
CTRL + r search history
CTRL + g escape from search mode
CTRL + p previous command in history
CTRL + n next command in history
ALT + . use the last word of the previous command
CTRL + - undo the last change
  • Command Control
shortcut action
CTRL + l clear the screen
CTRL + s stops the output to the screen
CTRL + q reenable the screen
CTRL + c terminate current foreground process
CTRL + z suspend current foreground process
  • Bash Bang(!) Commands
shortcut action
!! run last command
!blah run the most recent command that starts with β€˜blah’
!blah:p print out the command that !blah would run
!$ the last word of the previous command (same as Alt + .)
!$:p print out the word that !$ would substitute
!* the previous command except for the last word
!*:p print out what !* would substitute

Problems

cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{ print $2, $1}'
awk '
{ 
    for (i = 1; i <= NF; i++) {
        if (NR == 1) {
            s[i] = $i;
        } else {
            s[i] = s[i] " " $i;
        }
    }
}
END {
    for (i = 1; s[i] != ""; ++i) {
        print s[i];
    }
}' file.txt

Style Guide