2018年7月22日 星期日

bash: SHELL BUILTIN COMMANDS

內建指令是 shell 本身提供的指令,有些 shell 用外部指令取代。

除非特別說明,接受「-」開頭選項的內建指令也接受「--」來表示選項的結束。但「:」、「true」、「false」、及「test」並不接受選項,也就不處理「--」。「exit」、「logout」、「break」、「continue」、「let」、及「shift」接受及處理「-」開始的引數,不需要「--」作為結束。其它接受引數、但不接受選項的內建指令,「-」開始的引數會解釋為無效的選項,需要「--」來避免這種情況。

: [arguments]

只是擴展 arguments 及進行指定的轉向。

.  filename [arguments]
source filename [arguments]

在當下的 shell 環境執行 filename。如果 filename 不含 slash,會去 PATH 找 filename (不需要可執行)。如果 bash 不在 posix  模式,會再找目前目錄。如果內建指令 shopt 的選項 sourcepath 關閉,不找 PATH。如果有任何 arguments,會成為位置參數。

如果 -T 選項啟用,繼承 DEBUG trap。如果沒啟用,DEBUG trap 字串會備份後清掉,執行完再回復。參考內建指令 set。

alias [-p] [name[=value] ...]

bg [jobspec ...]


bind [-m keymap] [-lpsvPSVX]
bind [-m keymap] [-q function] [-u function] [-r keyseq]
bind [-m keymap] -f filename
bind [-m keymap] -x keyseq:shell-command
bind [-m keymap] keyseq:function-name
bind [-m keymap] keyseq:readline-command

bash readline 按鍵對應功能的顯示和綁定、或設定 readline 變數。

每個非選項的引數是如同 .inputrc 的指令,但 binding 跟 command 需要用不同引數傳遞
。例如「"\C-x\C-r":  re-read-init-file」.

選項:
  • -m keymap:keymap 可為 emacs (emacs-standard)、emacs-meta、emacs-ctlx、vi (vi-command)、vi-move、及 vi-insert,影響後續的綁定。
  • -l:列出所有 readline 功能名稱
  • -p:顯示 readline 功能名稱及綁定 (可輸入格式)
  • -P:顯示 readline 功能名稱及綁定
  • -s:顯示 readline key sequences bound to macros and the strings they output (可輸入格式)
  • -S:顯示 readline key sequences bound to macros and the strings they output.
  • -v:顯示 readline 變數名稱及值 (可輸入格式)
  • -V:顯示 readline 變數名稱及值
  • -f filename:自 filename 讀取 key bindings
  • -q function:詢問 function 綁定的 key
  • -u function:取消 function 綁定的 key
  • -r keyseq:移除任何目前 keyseq 的綁定
  • -x keyseq:shell-command:輸入 keyseq 執行 shell-command。shell-command 執行時, shell 設定變數 READLINE_LINE 為 readline line buffer 內容及 READLINE_POINT 為目前游標位置。如果執行的指令改變 READLINE_LINE 或 READLINE_POINT 的值,將會反應在編輯狀態。
  • -X:列出綁定到 shell command 的 key sequence 和 shell command (可輸入格式)

break [n]

跳脫 n 層 for、while、until、或 select 迴圈,n 預設為 1。

builtin shell-builtin [arguments]

用內建指令執行。
當定義的 function 名稱跟內建指令相同時,用來強制使用內建指令。

內建指令 cd 常常用 function 重新定義。

如果 shell-builtin 不是一個內建指令,回傳值是 false。

caller [expr]


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


command [-pVv] command [arg ...]


compgen [option] [word]


complete [-abcdefgjksuv] [-o comp-option] [-DE] [-A action]  [-G glob‐pat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] name [name ...]
complete -pr [-DE] [name ...]


compopt [-o option] [-DE] [+o option] [name]


continue [n]

直接開始下一回 for、while、until、或 select 的控制迴圈。如果有 n,開始第 n 層封閉迴圈。如果 n 超出所有封閉迴圈層數,則使用最外層。

declare [-aAfFgilnrtux] [-p] [name[=value] ...]
typeset [-aAfFgilnrtux] [-p] [name[=value] ...]


dirs [-clpv] [+n] [-n]


disown [-ar] [-h] [jobspec ... | pid ... ]


echo [-neE] [arg ...]


enable [-a] [-dnps] [-f filename] [name ...]

啟用及停用內建指令。
停用某個內建指令可以不用指令完整路徑執行同名的外部指令

範例:
  • `enable -n test` 停用內建指令 test
  • `enable test` 啟用內建指令 test
  • `enable` 或 `enable -p` 列出啟用的內建指令
  • `enable -n` 列出停用的內建指令
  • `enable -a` 列出所有內建指令,無論啟用及停用的
  • `enable -s` 列出啟用的 POSIX 內建指令
  • `enable -f filename name` 載入 filename (shared object 檔) 作為內建指令 name。
  • `enable -d` 移除之前透過 -f 載入的內建指令

eval [arg ...]

exec [-cl] [-a name] [command [arguments]]

執行 command 取代原本 process。
  • -l:在引數 0 前置「-」,如同指令 login。
  • -c:以空的環境變數執行。
  • -a name:使用 name 作為引數 0 (指令名稱)
shopt 選項 execfail 啟用:command 在非 interactive shell 無法執行時,不離開,改回傳失敗。

exit [n]


export [-fn] [name[=word]] ...
export -p


fc [-e ename] [-lnr] [first] [last]
fc -s [pat=rep] [cmd]


fg [jobspec]


getopts optstring name [args]


hash [-lr] [-p filename] [-dt] [name]

help [-dms] [pattern]


history [n]
history -c
history -d offset
history -anrw [filename]
history -p arg [arg ...]
history -s arg [arg ...]


jobs [-lnprs] [ jobspec ... ]
jobs -x command [ args ... ]


kill [-s sigspec | -n signum | -sigspec] [pid | jobspec] ...
kill -l|-L [sigspec | exit_status]


let arg [arg ...]

每個 arg 是要 evaluated 的 arithmetic expression。如果最後 arg evaluates 為 0,回傳 1,否則回傳 1。

local [option] [name[=value] ... | - ]


logout

登出,離開 login shell。

mapfile  [-d  delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
readarray [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]


popd [-n] [+n] [-n]


printf [-v var] format [arguments]


pushd [-n] [+n] [-n]
pushd [-n] [dir]


pwd [-LP]


read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]


readonly [-aAf] [-p] [name[=word] ...]


return [n]


set [--abefhkmnptuvxBCEHPT] [-o option-name] [arg ...]
set [+abefhkmnptuvxBCEHPT] [+o option-name] [arg ...]

shift [n]

所有位置參數往前位移 n 個位置,沒給 n 值時當作 1。n 超出範圍不動作,回傳失敗。

shopt [-pqsu] [-o] [optname ...]


suspend [-f]


test expr 或 [ expr ]


times

印出 shell 和透過其執行的累計使用者和系統時間。

trap [-lp] [[arg] sigspec ...]


type [-aftpP] name [name ...]


ulimit [-HSabcdefiklmnpqrstuvxPT [limit]]

控制 shell 和啟始的 process 可用的資源。選項 -H 及 -S 分別指定只設定 hard limt 或 soft limit,不然兩者都設。hard limit 設定之後只有 root 可以增加。soft limit 不能增加超過 hard limit。limit 可以是一個數字 (依據特定資源的單位),或是 hard、soft、或 unlimited 之一。如果省略 limit,預設印出目前的 soft limit,除非加 -H 選項。如果一次要印出多個資源,資源名稱及單位會印在值之前。參數沒指定資源時,預設是 -f,指檔案最大可寫入的大小。值大多以 1024-byte 為單位,-c 和 -f 在 posix 模式以 512-byte 為單位。其它選項說明如下:
  • -a:印出所有資源限制。
  • -b:最大 socket buffer 數目。
  • -c:最大建立的 core files 大小。
  • -d:最大 process 的 data segment 大小。
  • -e:最大 scheduling priority ("nice")。
  • -f:最大檔案可寫入的大小。
  • -i:最多 pending signals 的數目。
  • -k:最多可配置的 kqueue 數目。
  • -l:最大可 locked into memory 的大小。
  • -m:最大 resident set 大小 (許多系統不 honor this limit)。
  • -n:最多可開啟的 file descriptor (大部分系統不允許設定)。
  • -p:pipe 大小,以 512-byte block 為單位。(可能不能設。)
  • -q:在 POSIX message queues 最大 byte 數。
  • -r:最大 real-time scheduling priority。
  • -s:最大 stack 大小。
  • -t:最大 cpu time 秒數。
  • -u:單一使用者最多 process 數目。
  • -v:shell (或其 children) 最大 virtual memory。
  • -x:最多可鎖定的檔案數目。
  • -P :最多虛擬終端機數目。
  • -T:最大 thread 數目。

umask [-p] [-S] [mode]


unalias [-a] [name ...]

unset [-fv] [-n] [name ...]


wait [-n] [n ...]

參考來源

bash man page 的 SHELL BUILTIN COMMANDS

2018年7月21日 星期六

bash: DEFINITIONS, RESERVED WORDS & COMMENTS

定義
  • blank:space 或 tab 字元。
  • word 或 token:字,視為一個單元的一系列字元,由 metacharacter 切割。token 可以是字或運算子。
  • name 或 identifier:由英文字母、數字及「_」組成的字,不能以數字開頭,可作為 shell 變數或 function 名稱。
  • metacharacter:沒 quoted 時切割出 word 的字元,包括:
    • space、tab
    • 「<」與「>」:亦有輸出入導向功能 (redirection operator)
    • 「|」「&」「;」「(」「)」<newline>:組合出所有控制運算子 (control operator),亦區隔出子指令並控制執行方式。
  • control operator:進行執行控制功能的 token,包括:
    • 「|」或「|&」:串接前後指令的輸出入成為 pipeline。
    • 「&&」:AND,前面指令執行成功 (回傳值 0) 才執行下個指令。
    • 「||」:OR,前面指令執行失敗 (回傳值不為 0) 才執行下個指令。
    • 「&」:背景執行
    • 「;」或 <newline>:執行
    • ( ):subshell 執行
    • 「;;」、「;&」、「;;&」:用在 case
保留字:在 shell 有特殊意義的字,用在 simple command 第一個字 (見 bash SHELL GRAMMAR) 或指令 case、for 的第三個字。
  • !
  • case esac
  • coproc
  • do done
  • for
  • function
  • if then elif else fi
  • in select
  • until
  • while
  • { }
  • time
  • [[ ]]
註解
  • 字元 # 開始的字到行末都會忽略。互動式 shell 可用內建指令 shopt 的 interactive_comments 關閉註解功能。

參考來源

man bash 的 DEFINITIONS, RESERVED WORDS & COMMENTS 節

bash: ALIASES

alias 意思是「化名」。在 bash,每個 simple command 的第一個字符合某個 alias 名稱,會取代為對應的 alias 值。取代後的第一個字再繼續進行 alias,但如果是已經用過的 alias 名稱,就不再進行。例如 ls alias 為 ls -F 只會進行一次。如果 alias 的值的最後字元是一個 blank (依定義,blank 是 space 或 tab),指令下個字也進行 alias。

shell 有個 alias 列表,可透過內建指令 alias 和 unalias 來列出、設定和消除。alias 名稱不能包含字元 /、$、`、=、metacharacter 或 quoting 字元。alias 值可以包含任何 valid shell input,包括 metacharacters。

alias 用在互動式 shell,如果非互動式 shell 也要用,使用內建指令 shopt 設 expand_aliases。

alias 是在整行指令讀取時進行,而不是執行時進行。同行的新 alias 定義要等到指令執行完才會生效,並不會對同行指令生效。在 function 也是同樣的,alias 是在 function 定義讀取時進行,function 裡的新 alias 定義要等到 function 執行才會生效。安全的作法是把 alias 定義放在自己獨立一行,不要用在 compound command。

alias 進行優先於 shell function。

內建指令:alias [-p] [name[=value] ...]

alias 或 alisa -p 以 alias name=value 格式印出所有 alias 或印指定 name 的 alias。
設定 name 的 alias 為 value。

內建指令:unalias [-a] [name ...]

移除 alias 名稱 name。選項 -a 移除所有 alias。

shell 變數 BASH_ALIASES

由 alias 名稱作為 index 的一個  associative  陣列,成員是 alias 表。陣列新增成員會出現在 alias 表,但清除成員目前並不會從 alias 表移除。如果 unset BASH_ALIASES 會失去其特殊 properties。

列出 BASH_ALIASES
$ declare -p BASH_ALIASES

$ for k in "${!BASH_ALIASES[@]}"; do printf '%s => %s\n' "$k" "${BASH_ALIASES[$k]}"; done

參考來源

  1. bash 的 ALIASES 節、內建指令 alias、shell 變數 BASH_ALIASES
  2. https://unix.stackexchange.com/questions/109124/bash-aliases-not-equal-to-alias

bash: OPTIONS 和內建指令 set

bash 指令格式是 bash [--選項] [-選項] [引數],多字元選項「--選項」必須放在單字元選項「-選項」前面,之後是引數。通常第一個引數是指令 ($0),剩下引數傳給指令使用 ($1, $2, ...)。

單字元選項可使用內建指令 set 支援的單字元選項外,還可以用下列選項:
  • -c:第一個引數還是一樣是指令,但傳給指令的 $0 是第二個引數,位置參數 $1 從第三個引數開始。$0 作為警告和錯誤訊息的指令名稱。
  • -iinteractive shell
  • -l 或 --login:啟動為 login shell
  • -r:見 RESTRICTED SHELL
  • -s:指令從標準輸入讀取,不用引數的指令。在 interactive shell 設定為位置參數。
  • -D--dump-strings:在標準輸出印出所有前置 $ 的雙引號字串,當 locale 不為 C 或 POSIX 時會做語言轉換。隱含 -n 選項,不執行指令。
  • [-+]O [shopt_option]:-O 設定內建指令 shopt 的 shell 選項,+O 清掉。沒有 shopt_option 時,印出這些選項的名稱及值,如果用 +O 輸出可作為輸入的格式。
  • ---:表示選項結束,之後的引數視為檔名及其引數。
其它多字元選項:
  • --debugger:在 shell 開始前安排執行 debugger profile,啟用 extended 除錯模式 (見 bash 內建指令 shopt 選項 extdebug 的說明)
  • --dump-po-strings:相當於 -D,但以 GNU gettext po (portable object) 檔案格式輸出。
  • --help:顯示使用說明。
  • --init-file file--rcfile file:在 interactive shell 改執行 file 取代 /etc/bash.bashrc 及 ~/.bashrc (見 bash INVOCATION)。
  • --noediting:在 interactive shell 不使用 GNU readline 函式庫來讀取指令行。
  • --noprofile:不執行 /etc/profile、~/.bash_profile、~/.bash_login、或 ~/.profile。login shell 預設執行這些檔案 (見 bash INVOCATION)
  • --norc:在 interactive shell 不執行 /etc/bash.bashrc 及 ~/.bashrc。以 sh invoke 時預設啟用。
  • --posix:行為符合 POSIX 標準模式。見 SEE ALSO 參考  how posix mode affects bash's behavior 細節的文件。
  • --restricted:restricted shell (見 bash RESTRICTED SHELL).
  • --verbose:相當於 -v。
  • --version:顯示版本訊息。

內建指令 set

功能有設定 shell 選項、設定位置參數、列變數

set [--abefhkmnptuvxBCEHPT] [-o option-name] [arg ...]
set [+abefhkmnptuvxBCEHPT] [+o option-name] [arg ...]
set #依順序列出所有 shell 變數
set arg ... #依序設定位置參數 $1、$2、 ...

指令的選項用來設定或清除 shell 選項。除非特別說明,選項預設是關閉的。使用 --o 開啟選項,++o 關閉選項。

$- 可看到目前的選項。

指令選項說明如下:

-a 或 -o allexport

每個新建或更改的變數,export 到接下來指令的環境。

-b 或 -o notify

立刻回報結束的背景工作,而不是等到下個指令提示。

-e 或 -o errexit

待續

-f 或 -o noglob

停用 pathname 擴展。

-h 或 -o hashall

記憶執行時查到的指令路徑,預設是開啟的。

-k 或 -o keyword

待續

-m 或 -o monitor

待續

-n 或 -o noexec

讀取指令但不執行。可用來檢查 shell 指令搞是否有 syntax errors。在 interactive shell 沒作用。

-o option-name

沒 option-name 時列出目前 shell 選項設定,+o 顯示一系列 set 指令,可用來重新建立目前選項設定。

option-name 大多搭配有單字元格式,沒有的有:
  • emacs:使用 emacs-style 指令行編輯界面。interactive shell 預設啟用,除非 shell 時使用選項 --noediting。同時影響編輯界面用來讀取 -e。
  • history:啟用指令歷史功能 (見 bash HISTORY)。interactive shell 預設啟用。
  • ignoreeof:等同執行 shell 指令 ``IGNOREEOF=10''。(見 Shell Variables).
  • nolog:目前忽略
  • pipefail:回傳最後失敗指令的回傳值。
  • posix:使用 posix 模式。.
  • vi:使用 vi-style 指令行編輯界面。同時影響編輯界面用來讀取 -e。

-p 或 -o privileged

開啟特權 (privileged) 模式,此時 $ENV 及 $BASH_ENV 的檔案不處理,不自環境繼承 shell 函數,忽略變數 SHELLOPTS、BASHOPTS、CDPATH、及 GLOBIGNORE。
如果 shell 開始時的 effective user (group) ID 和 real user (group) ID 不同,也進行
這些動作。此時如果 -p 沒設,effective user id (group) 會設為 real user (group) id;如果有設,則不動 effective user (group) id。

-t 或 -o onecmd

讀完執行一個指令離開。

-u 或 -o nounset

待續

-v 或 -o verbose

印出讀到的輸入行。

-x 或 -o xtrace

trace 模式。擴展每個 simple command、for、case、select、或 arithmetic for 後,顯示 PS4 和指令。

-B 或 -o braceexpand

進行 brace expansion (見 bash Brace Expansion),預設啟用。

-C 或 -o noclobber

>,  >&,  and <> redirection operators 不覆寫存在的檔案。對 >| 則不影響。

-E 或 -o errtrace

待續

-H 或 -o histexpand

待續

-P 或 -o physical

待續

-T 或 -o functrace

待續

--

表示是最後的指令選項,接下來有引數的話,設定位置參數,否則重置位置參數。

-

表示是最後的指令選項,接下來有引數的話,設定位置參數。關閉指令選項 -x 和 -v。

參考來源

man bash OPTIONS 節、內建指令 set

2018年7月19日 星期四

TLPI: Creating a Daemon, Guidelines for Writing Daemons

初步了解 daemon 後,來看 daemon 建立的步驟:
  1. fork() 結束親行程,繼續的子行程呼叫 setsid() (TLPI §34.3) 成立新的行程群組。
    • 假設 daemon 是從指令行執行,親行程結束讓 shell 得以繼續,留下子行程在背景執行。
    • 親行程可能是行程群組領導,可能帶有其它子行程。fork() 後子行程就不會是領導,呼叫 setsid() 後成立新的獨立行程群組。
  2. 如果 daemon 之後需要開啟終端 device,需要動作確保不會變成控制終端,有兩種方式:
    • open() 任何終端 device 指定 O_NOCTTY 旗標。
    • 另一種較簡易的方式是進行第二次 fork(),一樣只讓子行程繼續執行。如此一來,子行程不會是行程群組領導,依據 Linux 跟隨的 the System V 只有領導取得控制終端機的傳統,可避免取得控制終端機 (TLPI §34.4)。如果是跟隨 BSD 傳統的系統,行程只有明確用 ioctl() TIOCSCTTY 設定後,才會得到控制終端機,第二次 fork() 是多餘的但也沒什麼傷害。
  3. 清除行程的 umask (TLPI §15.4.6),確保 daemon 建立檔案或目錄時,有需要的 permissions.
  4. 在 daemon 結束前,其工作目錄無法卸載 (TLPI §14.8.2),改變工作目錄到根目錄 ( / ) 或其它適當的目錄,可方便在 daemon 結束前卸載。
  5. 繼承的 file descriptor,沒用到的都關閉,以節省資源。 例如 daemon 已經失去控制終端,保留 file descriptors 0、1、和 2 並無意義。例外,開啟的檔案所在的檔案系統無法卸載。
  6. 將 file descriptors 0、1、和 2 都導到 /dev/null。
    • 避免 daemon 呼叫函式庫有輸出無法輸出,造成非預期的錯誤。
    • 避免 daemon 後續開啟檔案使用到 1 和 2,函式庫輸出而造成破壞。
glibc 提供不是標準的函數 daemon() 可轉換呼叫的程式為 daemon,下面是另一個實作的範例。

#include <sys/stat.h>
#include <fcntl.h>
#include "tlpi_hdr.h"
int                             /* Returns 0 on success, -1 on error */
becomeDaemon(int flags)
{
    int maxfd, fd;
    switch (fork()) {                   /* Become background process */
        case -1: return -1;
        case 0:  break;                 /* Child falls through... */
        default: _exit(EXIT_SUCCESS);   /* while parent terminates */
    }
    if (setsid() == -1)                 /* Become leader of new session */
        return -1;
    switch (fork()) {                   /* Ensure we are not session leader */
        case -1: return -1;
        case 0:  break;
        default: _exit(EXIT_SUCCESS);
    }
    if (!(flags & BD_NO_UMASK0))
        umask(0);                       /* Clear file mode creation mask */
    if (!(flags & BD_NO_CHDIR))
        chdir("/");                     /* Change to root directory */
    if (!(flags & BD_NO_CLOSE_FILES)) { /* Close all open files */
        maxfd = sysconf(_SC_OPEN_MAX);
        if (maxfd == -1)                /* Limit is indeterminate... */
            maxfd = BD_MAX_CLOSE;       /* so take a guess */
        for (fd = 0; fd < maxfd; fd++)
            close(fd);
    }
    if (!(flags & BD_NO_REOPEN_STD_FDS)) {
        close(STDIN_FILENO);            /* Reopen standard fd's to /dev/null */
        fd = open("/dev/null", O_RDWR);
        if (fd != STDIN_FILENO)         /* 'fd' should be 0 */
            return -1;
        if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO)
            return -1;
        if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
            return -1;
    }
    return 0;
}

寫一個程式呼叫 becomeDaemon(0),然後 sleep() 一陣子,可以用指令 ps 來看程式的一些屬性:
$ ./test_become_daemon
$ ps -C test_become_daemon -o "pid ppid pgid sid tty command"
  PID  PPID  PGID   SID TT       COMMAND
24731     1 24730 24730 ?        ./test_become_daemon
TT 下顯示 ? 表示沒有控制終端機。SID 不同於 PID,表示不是 session leader,不會再取得控制終端機。

由於 daemons 是長時間執行。需要特別注意可能的記憶體洩漏 (TLPI §7.1.3) 和 file descriptor 洩漏 (沒有關閉所有開啟的 file descriptor。程式結束不是全部自動關閉嗎?)。

daemon 通常是系統結束時呼叫其 shutdown script,沒有的則由 init process 送 SIGTERM,5 秒後再送 SIGKILL。

許多 daemon 需要確保一個時間只有一個在執行,方法見 TLPI §55.6。

參考來源

  1. TLPI §37.2 & §37.3

bash

GNU 的 Bash (Bourne-Again SHell) 是一個指令語言直譯器,執行來自標準輸入或檔案的指令,與 sh 相容並結合 Korn shell (ksh) 及 C shell (csh) 的優點,相容 IEEE POSIX 標準的 Shell and Utilities 部份。

指令格式:
bash [options] [command_string | file]
整個指令由空白字元分成許多字,一開始可有一些選項 (option)。如果選項沒設 -c 或 -s 且之後還有引數,第一個引數會認定是一個檔名,並設為 $0。之後的引數依序設為位置參數 $1、$2、...。bash 會讀取並執行檔案內的指令,然後離開,離開狀態碼預設 0,最後執行的指令有最後決定權。檔案首先會在目前目錄找,如沒有再找 PATH 指定的目錄。

INVOCATION
DEFINITIONS, RESERVED WORDS, & COMMENTS
SHELL GRAMMAR
QUOTING
PARAMETERS
EXPANSION
REDIRECTION
ALIASES 別名
FUNCTIONS
ARITHMETIC EVALUATION
CONDITIONAL EXPRESSIONS
SIMPLE COMMAND EXPANSION
COMMAND EXECUTION
COMMAND EXECUTION ENVIRONMENT
ENVIRONMENT
EXIT STATUS 結束狀態
SIGNALS
JOB CONTROL
PROMPTING
READLINE
HISTORY
HISTORY EXPANSION
SHELL BUILTIN COMMANDS 內建指令
RESTRICTED SHELL
SEE ALSO
FILES

參考來源
  1. man bash
延伸閱讀

2018年7月18日 星期三

nc

netcat 在 Linux 中的指令為 nc,網路的 cat 工具程式,透過網路連結 stdin 和 stdout,原汁原味傳送資料。另外也可以掃描通訊埠。

     nc [-46bCDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl] [-m minttl]
        [-O length] [-P proxy_username] [-p source_port] [-q seconds]
        [-s source] [-T keyword] [-V rtable] [-w timeout] [-X proxy_protocol]
        [-x proxy_address[:port]] [destination] [port]

nc 可作為基於指令稿的 Client 或 Server,可用在 TCP、UDP、或 UNIX-domain sockets,作通訊埠掃描,可處理 IPv4 和 IPv6。
  • destination 是 IP 位址或主機名稱,當伺服器端時 (使用 -l 選項) 不指定是指本機。在 UNIX-domain 是 socket 路徑。
  • port 可以是數字或服務名稱,或數字範圍。

使用可直接看下面範例。

    基本 client/server 連線

    在特定埠等待連線,server 端使用選項 -l (listen 等待進來連線。不能搭配選項 -p、-s、-z 使用,-w timeout 選項沒作用。)
    $ nc -l 1234
    在另一個終端機當 client,進行連線
    $ nc 127.0.0.1 1234
    任何一方的輸入,在另一方會出現。Ctrl-C 結束連線 (EOF (‘^D’) ?)。

    nc 沒有選項將收到的資料作為指令執行 (例如其它指令的選項 -c 或 -e),但可透過輸出轉向和 fifo 解決。server 輸出導給 fifo,取出給 /bin/sh 執行,再將結果傳給 server 顯示到 client。
    伺服器端:
    $ rm -f /tmp/f; mkfifo /tmp/f
    $ cat /tmp/f | /bin/sh -i 2>&1 | nc -l 127.0.0.1 1234 > /tmp/f
    使用者端:
    $ nc host.example.com 1234
    $ (shell prompt from host.example.com)
    註:busybox nc 有 -e 選項。

    當連線結束,nc 就結束。想要持續 listening 使用 -k 選項。

    傳送檔案

    接收端:
    $ nc -l 1234 > filename.out
    傳送端:
    $ nc -N host.example.com 1234 < filename.in

    傳送目錄

    接收端:
    nc -l 1234 | tar xvf -

    傳送端:
    tar cvf - /path/to/dir | nc host.example.com 1234

    遠端備份硬碟

    接收端:
    nc -l 1234 | dd of=sdb-backup.img.gz
    傳送端:
    dd if=/dev/sdb | gzip -c | nc hostB.com 1234
    回復接收端:
    nc -l 5000 | gzip -d | sudo dd of=/dev/sdb
    回復傳送端:
    nc hostA.com 5000 < sdb-backup.img.gz

    連線到伺服器

    取網頁:(註:echo 參數,n 不送換行,e 解釋反斜線跳脫。)
    $ echo -ne "GET / HTTP/1.0\r\n\r\n" | nc host.example.com 80
    送電子郵件到 SMTP 伺服器:
    $ nc [-C] localhost 25 << EOF
    HELO host.example.com
    MAIL FROM:<user@host.example.com>
    RCPT TO:<user2@host.example.com>
    DATA
    Body of email.
    .
    QUIT
    EOF

    偵測通訊埠

    用 -v 選項啟用 stderr verbose 輸出
    $ nc -v host.example.com 1234
    nc: connect to host.example.com (tcp) failed: Connection refused
    有開啟的話,通常 greeting banner 訊息含有伺服器執行的軟體和版本:
    $ nc -v host.example.com 22
    Connection to host.example.com 22 port [tcp/ssh] succeeded!
    SSH-2.0-OpenSSH_6.0p1 Debian-4
    使用 -z 選項和依序掃描通訊埠範圍:
    $ nc -zv host.example.com 20-30
    Connection to host.example.com 22 port [tcp/ssh] succeeded!
    Connection to host.example.com 25 port [tcp/smtp] succeeded!
    指定掃描的埠:
    $ nc -zv host.example.com 80 20 22
    nc: connect to host.example.com 80 (tcp) failed: Connection refused
    nc: connect to host.example.com 20 (tcp) failed: Connection refused
    Connection to host.example.com port [tcp/ssh] succeeded!
    掃描通訊埠範圍取得 greeting banners 才斷開連線,可透過 -w 指定短 timeout 或送「QUIT」指令給伺服器:
    $ echo "QUIT" | nc host.example.com 20-30
    SSH-1.99-OpenSSH_3.6.1p2
    Protocol mismatch.
    220 host.example.com IMS SMTP Receiver Version 0.84 Ready
    使用 -uz 選項的 UDP port 掃描不論有沒有都會回報成功 (有送出就成功?),可用 traffic sniffer 查看封包。

    送測試 UDP 封包
    echo -n "foo" | nc -u -w1 host.example.com 1234
    接收:
    nc -lu 1234

    其它範例

    TCP 連線到 host.example.com:42,使用 31337 最為來源埠,timeout 5 秒:
    $ nc -p 31337 -w 5 host.example.com 42
    UDP 連線到 host.example.com:53:
    $ nc -u host.example.com 53
    TCP 連線到 host.example.com:42,使用 10.1.2.3 作為來源 IP:
    $ nc -s 10.1.2.3 host.example.com 42
    接收 UNIX-domain stream socket 的連線:
    $ nc -lU /var/tmp/dsocket
    透過 HTTP proxy 10.2.3.4:8080 連線到 host.example.com:42。見 ssh_config 的 ProxyCommand directive 搭配 ssh 使用。
    $ nc -x10.2.3.4:8080 -Xconnect host.example.com 42
    透過有認證的 HTTP proxy 連線:
    $ nc -x10.2.3.4:8080 -Xconnect -Pruser host.example.com 42

    其它選項說明

    • -4:只用 IPv4 位址
    • -6:只用 IPv6 位址
    • -b:允許廣播
    • -C:送 CRLF 作為 line-ending
    • -D:啟用 socket 除錯
    • -d:不嘗試讀取 stdin
    • -F:使用 sendmsg() Pass the first connected socket 到 stdout 後離開。使用 -X 選項跟 proxy 進行連線後,把連線留給其它程式,例如 ssh() 使用 ssh_config ProxyUseFdpass 選項。
    • -h:印出 help
    • -I length:指定 TCP 接收 buffer 大小。
    • -i interval:指定每行送收間的延遲時間。同時導致連線多個通訊埠的延遲時間。
    • -k:連線結束後持續等待其它連線,需搭配 datagram 選項 (-u) 使用。
    • -M ttl:設送出封包的 TTL。
    • -m minttl:請求 kernel 拋棄進來封包 TTL 小於 minttl 的。
    • -N:輸入 EOF 後 shutdown() 網路 socket。有些伺服器需要這樣才能完成工作。
    • -n:不對指定的位址、主機名稱、或通訊埠進行 DNS service lookup。
    • -O length:指定 TCP 傳送 buffer 大小。
    • -P proxy_username:指定 HTTP proxy 認證的使用者名稱。
    • -p source_port:指定使用的來源通訊埠。subject to privilege restrictions and availability。
    • -q seconds:在 stdin 的 EOF 後,等候後才離開 (implies -N)。如果是負數,wait forever。
    • -r:在範圍內,以亂數方式選擇通訊埠。
    • -S:啟用 RFC 2385 TCP MD5 signature 選項。
    • -s source:指定來源 IP 或 UNIX-domain socket 檔案。
    • -T keyword:設定 IPv4 ToS 值,可以是 critical、inetcontrol、lowcost、lowdelay、netcontrol、throughput、reliability、或 DiffServ Code Point (ef、af11、...、af43、cs0、...、cs7)、或十六進位或十進位數字。
    • -t:送 RFC 854 DON'T and WON'T response to RFC 854 DO and WILL 請求,讓 nc script telnet session。
    • -U:使用 UNIX-domain socket。
    • -u:使用 datagram。
    • -V rtable:設定使用的 routing table。
    • -v:verbose 輸出。
    • -w timeout:對外連線的 timeout。
    • -X proxy_protocol:使用的 proxy 協定,4 是 SOCKS v.4、5 是 SOCKS v.5、connect 是 HTTPS proxy。預設是使用 SOCKS v.5。
    • -x proxy_address[:port]:proxy 的位址。
    • -Z:DCCP 模式。
    • -z:進行掃描。

    參考來源

    1. man nc
    2. http://blog.gtwang.org/linux/linux-utility-netcat-examples/

    延伸閱讀

    SIP header Via

    所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...