- Abstract
- References
- Shell Metachars
- Basic Usages
- Basic Shell Features
- Shell Builtin Commands
- Shell Variables
- Bash Features
- Job Control
- Command Line Editing
- Using History Interactively
- Installing Bash
- Job Control Advanced
- Signals
- Short Cuts
- Problems
- Style Guide
bash reference manual | gnu μ μ½κ³ μ 리νλ€.
- GitHub Enterprise Backup Utilities | github
- source code λ₯Ό μ°Έκ³ ν λ§ νλ€.
- Bash script
- νκΈ κ°μ΄λ
- bash reference manual | gnu
- Advanced Bash-Scripting Guide
- bash repo
metachars λ command μ λ€λ₯΄κ² μ²λ¦¬λκΈ° λλ¬Έμ command line μ ν¬ν¨νλ κ²½μ° escape νκ±°λ quote ν΄μ μ¬μ©ν΄μΌ νλ€.
( ) ` | & ; # Command substitution
&& || # AND, OR
< > >> # Redirection
* ? [ ] # Glob
" ' # Quote
\ $
= +=
$ 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
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 λ₯Ό μμ§νλ€.
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 ('
) preserve the literal value of each character within the
quotes.
$ echo 'Hello, $USER!'
Hello, $USER!
Double quotes ("
) preserve the literal value of all characters within the
quotes, except for $
, `` , and \
.
$ echo "Hello, $USER!"
Hello, <username>!
Using $''
allows interpreting certain escaped characters according to the
ANSI-C standard.
$ echo $'Hello,\nWorld!'
Hello,
World!
Using $""
allows translating strings according to the current locale settings.
# assuming a Spanish locale
$ echo $"Hello, World!"
Β‘Hola, Mundo!
Comments start with the #
character and continue until the end of the line.
# This is a comment
echo "This is not a comment"
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
A simple command is a sequence of words separated by spaces or tabs.
$ ls -l
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 are sequences of commands that are executed sequentially,
possibly separated by the ;
, &
, &&
, or ||
operators.
$ echo "Hello,"; echo " World!"
There are several looping constructs: for
, while
, until
.
for i in {1..3}; do
echo "$i"
done
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 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 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 allows executing commands in parallel, making use of multiple CPU cores to speed up execution.
$ parallel 'echo {}' ::: 1 2 3 4
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"
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 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 are transformations applied to shell commands and allow complex operations in the command line.
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 substitutes the tilde (~
) with the value of the home directory.
cd ~/Downloads
# Navigates to the user's Downloads folder.
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 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 substitutes an arithmetic expression with its result.
This will output 10.
echo $((5 + 5))
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)
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 or globbing matches filenames using wildcards.
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 removes quotations around arguments, allowing the shell to interpret them correctly.
# This sets VAR to Hello, World! without the quotes.
VAR="Hello, World!"
Redirections are used to change the input/output destinations of commands in bash.
To redirect input from a file to a command, use <
followed by the filename.
sort < input.txt
To redirect the output of a command to a file, use >
followed by the filename.
Example:
ls > list.txt
To append the output of a command to a file, use >> followed by the filename.
echo "Appended line" >> file.txt
To redirect both standard output and standard error to a file, use &>
followed
by the filename.
command &> output_and_errors.txt
To append both standard output and standard error to a file, use &>>
followed
by the filename.
command &>> output_and_errors.txt
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 are used to provide a string as input to a command.
tr '[:lower:]' '[:upper:]' <<< "hello world"
To duplicate a file descriptor, use >&
.
# This command duplicates file descriptor 3 to standard output (file descriptor 1).
command 3>&1
To move a file descriptor, use <&
.
# This command moves file descriptor 3 to standard output (file descriptor 1).
command 3<&1
To open a file descriptor for reading and writing, use <>
.
exec 3<> file.txt
Command expansion allows the output of a command to be used as an argument in another command.
echo "Today is $(date)"
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
The command execution environment includes the command, arguments, environment variables, and file descriptors.
$ env | sort
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 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 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
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 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 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 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"
There are built-in commands that can be used to modify the behavior of the Bash shell.
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
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 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 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.
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
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 has various features that enhance its capabilities as a shell.
Invoking Bash involves starting a new instance of the shell, which can execute scripts or commands interactively.
bash script.sh
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'
An interactive shell is a shell that allows interaction with the user, usually by typing commands.
An interactive shell allows you to run commands and see their output immediately.
$ echo "Hello, World!"
Hello, World!
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 shells provide features like command history, tab completion, and aliases.
$ history
1 ls
2 cd ..
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
Bash supports arithmetic operations using $(())
or $[]
.
$ echo $((5 * 3))
15
Aliases are shorthand commands that are created by mapping a string to a command.
$ alias ll='ls -la'
$ alias ll
$ type ll
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 is a list of directories in Bash that can be navigated using
pushd
, popd
, and dirs
.
pushd
, popd
, and dirs
are built-in commands that help manipulate and
navigate the directory stack.
$ pushd /etc
$ dirs
/etc ~/mydir
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\]\$ '
A restricted shell is a shell that has limited capabilities to restrict the user's actions.
$ rbash
Bash can be run in POSIX mode to be compatible with the POSIX standard for better portability.
$ bash --posix
Bash can be invoked in compatibility mode to emulate the behavior of other shells, like sh.
$ bash --sh
Job control allows users to manage multiple processes (jobs) running concurrently.
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
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
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
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 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.
Basic commands to navigate the command line:
Control + A
: Move to the beginning of the lineControl + E
: Move to the end of the lineControl + B
: Move backward one characterControl + F
: Move forward one characterControl + W
: Delete previous wordControl + K
: Delete from the current cursor position to the end of the lineControl + U
: Delete from the current cursor position to the beginning of the line
Alt + B
: Move backward one wordAlt + F
: Move forward one wordControl + XX
: Toggle between current and previous cursor positions
Killing refers to cutting text, which can later be pasted (yanked) elsewhere.
Control + K
: Kill from cursor position to end of lineControl + U
: Kill from cursor position to beginning of lineAlt + D
: Kill from cursor position to end of current wordAlt + Backspace
: Kill from cursor position to beginning of current word
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 charactersAlt + 3 Control + K
: Kill the next three characters
Control + R
: Search for a previously executed command by typing its partial string
The readline init file (~/.inputrc
or /etc/inputrc
) provides custom
configurations for readline keybindings and settings.
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 constructs allow you to specify different settings for different programs or terminal types.
$if Bash
$endif
# ~/.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
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.
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.
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.
complete
: Specify completion behavior for a specific commandcompgen
: Generate completion matchescompopt
: Modify completion options for a specific command
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
).
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 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
!
: 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 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 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
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
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"
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
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
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
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
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
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
$ 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
λ€μκ³Ό κ°μ΄ 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
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
jobs
jobs
νμ¬ job table λͺ©λ‘μ 보μ¬μ€λ€.jobs -l
show job table with process id%+
job spec which means current job%-
job spec which means previous jobjobs -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 κ° κ°λ₯νλ€.
- stop until get the
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 ν μ μλ€.
Ctrl c
- send the
SIGINT
signal to foreground job.
- send the
Ctrl z
- send the
SIGTSTP
signal (suspend) to foreground job and make the background job the foreground job.
- send the
- Input
- μ
λ ₯μ foreground job μμλ§ κ°λ₯ν©λλ€. background job μμ μ
λ ₯μ λ°κ²λλ©΄
SIGTTIN
μ νΈκ° μ λ¬λμ΄ suspend λλ€.
- μ
λ ₯μ foreground job μμλ§ κ°λ₯ν©λλ€. background job μμ μ
λ ₯μ λ°κ²λλ©΄
- Output
- μΆλ ₯μ νμ¬ session μμ μ€νλκ³ μλ λͺ¨λ job λ€μ΄ 곡μ νλ€.
stty tostop
μ μ¬μ©νλ©΄ background job μμ μΆλ ₯μ΄ λ°μνμ λ suspend μν¬ μ μλ€.
- μΆλ ₯μ νμ¬ session μμ μ€νλκ³ μλ λͺ¨λ job λ€μ΄ 곡μ νλ€.
$ AA=100; echo $$ $BASHPID;
15 15
$ { AA=200; echo $$ $BASHPID; } &
[1] 70
$ 15 70
[1]+ Done { AA=200; echo $$ $BASHPID; }
$ echo $AA
100
μ€ν¬λ¦½νΈ νμΌμ μ€ν λμ€μ background λ‘ λͺ
λ Ήμ μ€ννλ©΄ μ€νλλ λͺ
λ Ήμ job
table μ λνλμ§ μκ³ stdin μ /dev/null
μ μ°κ²°λλ€. parent process μ
ν΄λΉνλ μ€ν¬λ¦½νΈ νμΌμ΄ λ©΄μ μ’
λ£νλ©΄ PPID κ° init μΌλ‘ λ°λμ΄ μ€νμ
κ³μνλ―λ‘ daemon μΌλ‘ λ§λ€ μ μλ€.
- prompt μμ exit λ logout μΌλ‘ μ’
λ£νλ κ²½μ°
- background job μ΄ stopped μΈ κ²½μ°
- prompt μ job μ΄ μ’ λ£λμλ€κ³ μλ €μ€λ€.
- background job μ΄ running μΈ κ²½μ°
- ppid κ° init μΌλ‘ λ°λλ€.
- login shell μΈ κ²½μ°
shopt -s huponexit
κ° μ€μ λμλ€λ©΄ logout νμ λ λͺ¨λ running background job λ€μ΄SIGHUP
μ μμ νκ³ μ’ λ£νλ€.
- background job μ΄ stopped μΈ κ²½μ°
- μλμ°μμ terminal program μ μ’
λ£νκ±°λ μμ€ν
μ΄ μ’
λ£λλ κ²½μ°
- remote login μμ λ€νΈμ, λͺ¨λ μ°κ²°μ΄ λκΈ°κ±°λ interactive shell μ
kill -HUP
μ νΈλ₯Ό μ£Όλ κ²½μ°λ ν΄λΉνλ€. - shell μ stopped, running job λ€μ΄ λͺ¨λ
SIGHUP
μ λ°κ³ μ’ λ£νλ€.
- remote login μμ λ€νΈμ, λͺ¨λ μ°κ²°μ΄ λκΈ°κ±°λ interactive shell μ
ν°λ―Έλμ μ΄λ©΄ 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 μ 보λ΄λ λ°©λ²μ΄λ€.
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
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
...
$ 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
λ 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 μ 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
λ νΉμν νμΌμ΄κ³ process μ controlling terminal κ³Ό κ°λ€. νμ¬ ctty
κ° /dev/pts/12
μ΄λΌλ©΄ /dev/tty
λ /dev/pts/12
μ κ°λ€κ³ ν μ μμ΅λλ€
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 λͺ
λ Ήμ λ€μκ³Ό κ°μ μν μ
μννλ€.
- 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.
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 |
read
function μ 0 byte λ₯Ό μ½μΌλ©΄ λͺ¨λ μ½μλ€κ³ νλ¨νκ³ μ’
λ£νλ€. 0 byte κ°
곧 end of file
μ΄λ€. Ctrl-D
κ° κ³§ EOF λ₯Ό μλ―Ένλ€.
λκ°μ νλ‘μΈμ€κ° stdout, stderr μ μΆλ ₯μ μννλ€λ©΄ race condition μ΄
λ°μνλ€. λ€μμ f()
μ 첫λ²μ§Έ echo
κ° λλ²μ§Έ echo
μ κ²½ν©μ λ²μ¬μ
λΉ¨κ°μμ μΆλ ₯νλ κ²½μ°μ΄λ€.
f() {
{ echo 111; date; echo 222; } &
{ echo -en "\e[31m"; sleep 1; echo -en "\e[m"; } >&2
}
terminal μ΄ μμ΄μ‘λ€λ κ²μ μλ―Ένλ€. ν°λ―Έλμ΄ μ‘΄μ¬νμ§ μμΌλ©΄ λͺ
λ Ήμ μ
λ ₯ν
μλ, κ²°κ³Όλ₯Ό μΆλ ₯ν μλ μλ€. remote login μμ λ·νΈμ, λͺ¨λ μ°κ²°μ΄ λκΈ°κ±°λ
λλ μ¬μ©μκ° ν°λ―Έλ νλ‘κ·Έλ¨μ μ’
λ£μν€λ©΄ shell μ SIGHUP
μ νΈκ° μ λ¬λλ€.
interactive shell μ΄ SIGHUP
μ μμ νλ©΄ stopped, running job λ€λ SIGHUP
μ
μμ νλ€.
λ 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
μ μ΄μ©νλ©΄ νλμ λΈλ‘μ νλμ 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 μΌλ‘ critical section μ ꡬνν΄ λ³΄μ.
$ export -f func1
$ flock /var/lock/mylock -c 'func1 11 22 33'
κΈ°μ‘΄μ μ€ν¬λ¦½νΈλ₯Ό μμ νμ§ μκ³ flock μΌλ‘ critical section μ ꡬνν΄ λ³΄μ.
flock -n /var/lock/mylock ./script.sh
flock -o
μ μ¬μ©νλ©΄ server.sh
κ° μ€νλ λ lock μ μμ νμ§ μλλ€.
flock -n -o /var/lock/mylock ./server.sh
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" "$@" || :
# 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
μ μ΄μ©νμ¬ 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
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() { ...;}
- 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 |
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