Linux Shell 腳本攻略

第1章 小試牛刀

  • $ 是普通用戶,# 表示管理員用戶 root。

  • shebang:#!。sharp / hash / mesh 稱呼 #,bang 稱呼 !。后接解釋器命令路徑。

  • 兩種運行腳本方式:作為命令行參數(shù)(無需 shebang),或授予腳本執(zhí)行權(quán)限。

  • echo后無引號或使用單引號,無須轉(zhuǎn)義字符 \;雙引號中使用轉(zhuǎn)義字符須使用-e;無引號時后面的文本中不能有;;變量替換在單引號中無效。

  • printf不像echo會自動添加換行符。取消echo自動添加換行符須使用-n。

  • %[-][n]s-為左對齊,n為字符串內(nèi)的字符數(shù),如n小于命令后對應(yīng)的字符串長度,則n被忽略。

  • 打印紅色文本,echo -e "\e[1;31m This is red text. \e[0m"。\e[1;31m將顏色設(shè)為紅色,\e[0m將顏色重置回。常用背景顏色代碼:重置=0,黑色=30,紅色=31,綠色=32,黃色=33,藍色=34,洋紅=35,青色=36,白色=37。常用背景顏色代碼:重置=0,黑色=40,紅色=41,綠色=42,黃色=43,藍色=44,洋紅=45,青色=46,白色=47。

  • Bash 中每一個變量的值都是字符串。

  • 進程的環(huán)境變量可用cat /proc/$PID/environ得到,PID 可用```pgrep```加進程名獲得。每個環(huán)境變量由 null 字符(\0)分隔,可用```cat /proc/PID/environ | tr '\0' '\n'```每行顯示一個,更清楚。

  • var=value是賦值操作,var = value是相等操作。

  • 獲取字符串長度${#var}。

  • 當前使用 shell:echo $SHELLecho $0

  • root 用戶的 $UID 是0。

  • PS1 是終端提示字符串。

  • 自定義添加路徑函數(shù):prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1 ; }。
    使用:prepend PATH /opt/myapp/bin

  • let result=no1+no2,result=$[ no1 + no2 ],result=$(( no1 + no2 )),三者等價。等號后的變量名前加$亦可。

  • 高精度計算:echo "scale=16; $no1 ^ $no2" | bc。此處 no2 必須為整數(shù)。

  • 重定向 stdin:0>(>)。重定向 stdout:1>(>)。重定向 stderr:2>(>)

  • tee屏顯加保存,僅保存 stdout。有-a為追加內(nèi)容,沒有為覆蓋。

  • 將 out 的內(nèi)容寫入 log.txt:
    out 文件內(nèi)容:

#!/bin/bash
cat << EOF > log.txt
hi
hello
EOF

運行 . out,log.txt 的內(nèi)容為:

hi
hello
  • 定義數(shù)組array_var=(1 2 3 4 5)。打印特定元素echo ${array_var[$index]}。以清單形式打印所有元素echo ${array_var[*]},或echo ${array_var[@]}。打印數(shù)組長度echo ${#array_var[*]}。列出數(shù)組索引echo ${!array_var[*]}。

  • 定義關(guān)聯(lián)數(shù)組(Bash 4.0 以上版本)declare -A ass_array。賦值 ass_array=([index1]=val1 [index2=val2]),或 ass_array[index1]=val1; ass_array[index2]=val2

  • 設(shè)置命令別名:alias new_command='command sequence'。

  • 不使用別名:\command。尤其對于特權(quán)命令,可避免攻擊者使用別名盜取信息。

  • 獲取終端行數(shù)和列數(shù):tput culs,tput lines。
    打印出當前終端名:tput longname
    將光標移到坐標(10,10)處:tput cup 10 10。
    設(shè)置終端背景色:tput setb n。n 可在0至7之間取值。
    設(shè)置終端前景色:tput setf n
    設(shè)置粗體:tput bold。
    設(shè)置下劃線:tput smul
    刪除從當前光標位置以后的所有內(nèi)容:tput ed。

  • 禁止將輸出發(fā)送到終端:

#!/bin/bash
echo -e "Enter password: "
stty -echo
read password
stty echo
echo
echo Password read.
  • 紀元時或 Unix 時間:自世界標準時間(UTC)1970年1月1日0時0分0秒起所流逝的秒數(shù)。

  • 當前紀元時:date +%s。
    日期串轉(zhuǎn)換成紀元時:date --date "Thu Nov 18 08:07:21 IST 2010" +%s--date用于提供日期串。
    轉(zhuǎn)換為星期幾:date --date "Jan 20 2001" +%A
    打印日期:date "+%s/S/M/I/H/d/b/B/m/y/Y/a/A/D"。
    設(shè)置日期:date -s "格式化的日期字符串"。

  • 倒計時:

#!/bin/bash
echo -n count:
tput sc
count=11
while true
do
    if [ $count -gt 0 ]
    then
        let count--
        sleep 1
        tput rc
        tput ed
        echo -n $count
        else exit 0
    fi
done
  • 啟用調(diào)試:bash -x script.sh。
    部分調(diào)試:
#!/bin/bash
for i in {1..6}
do
    set -x
    echo $i
    set +x
done
echo "Script executed."

執(zhí)行時顯示:-x。讀取時顯示:-v
#!/bin/bash改為#!/bin/bash -xv,則直接運行即可。
自定義調(diào)試信息:

#!/bin/bash
function DEBUG()
{
    [ "$_DEBUG" == "on" ] && $@ || :
}
for i in {1..10}
do
    DEBUG echo $i
done

此處echo $i即為調(diào)試信息。

  • 遞歸函數(shù):
    Fork Bomb
:(){ :|:& }; :

:()
{
    : | : &
}
:

: 為函數(shù)名。可通過ulimit -u 128(暫時)或修改配置文件 /etc/security/limits.conf 來限制可生成的最大進程數(shù)來避開。

  • 導(dǎo)出函數(shù):export -f fname。

  • 退出狀態(tài):$?。成功則為0,否則為非0。如果最后設(shè)置了exit n,則總返回 n。

  • 子 shell 法:cmd_output=$(ls | cat -n)。
    反引用或反標記法:cmd_output=`ls | cat -n`
    保留空格和換行符:echo "$cmd_output"。

  • 使用子 shell ()

pwd
(cd /bin; ls)
pwd

子 shell 中的命令對當前 shell 沒有影響。

  • 讀取 n 個字符并存入變量:read -n number_of_chars variable_name。
    用無回顯的方式讀取密碼:read -s var
    顯示提示信息:read -p "xxx" var。
    在特定時限內(nèi)讀取輸入:read -t timeout var
    用特定的定界符作為輸入行的結(jié)束:read -d ":" var。

  • 含延時重復(fù)函數(shù):

repeat()
{
    while true
    do
        $@ && return
        sleep 30
    done
}

更快的做法:repeat() { while :; do $@ && return; sleep 30; done}
:是內(nèi)建命令,總返回0。

  • 更改定界符:
data="name,sex,rollno,location"
oldIFS=$IFS
IFS=,
for item in $data
do
    echo Item: $item
done
IFS=$oldIFS
#!/bin/bash
line="root:x:0:0:root:/root:/bin/bash"
oldIFS=$IFS
IFS=:
count=0
for item in $line
do
    [ $count -eq 0 ] && user=$item
    [ $count -eq 6 ] && shell=$item
    let count++
done
IFS=$oldIFS
echo $user\'s shell is $shell
  • 條件為真則執(zhí)行 action:[ condition ] && action
    條件為假則執(zhí)行 action:[ condition ] || action。

  • 使用字符串比較時,最好用雙中括號,因為單中括號有時回產(chǎn)生錯誤。用test可以避免使用過多的括號。

第2章 命令之樂

  • 壓縮相鄰空白行:cat -s file。
    將制表符顯示為^Icat -T file,對排除縮進錯誤非常有用。
    顯示行號:cat -n file,空白行不標號則用-b。

  • 錄制終端會話:script -t 2> timing.log -a output.session,之后進行命令行操作,以exit結(jié)束錄制。
    播放:scriptreplay timing.log output.session。

  • find .類似ls。find . -print0將以 NULL 取代空格作為分隔符,在文件名中含空格時有用。
    忽略字母大小寫: find path -iname。
    匹配多個條件中的一個:\( -name "*.txt" -o -name "*.pdf" \)。
    同時搜索文件和文件夾:-path
    正則表達式搜索:-regex或忽略大小寫-iregex。
    否定參數(shù):! -name。
    限制目錄深度:最大深度-maxdepth,開始的最小深度-mindepth。這個選項應(yīng)該放在最前面,以避免多余的搜索。
    按類型搜索:-type f/l/d/c/b/s/p。
    按時間搜索:最近7天內(nèi)訪問過-atime -7,恰好7天前修改過-mtime 7,超過7天前變化過-ctime +7。如計量時間為分鐘,則用-amin/-mmin/-cmin。比參考文件更新-newer file_to_be_compared。
    按大小搜索:-size nb/c/w/k/M/G
    刪除找到的文件:在最后加-delete。
    按特定權(quán)限搜索:-perm
    按所有權(quán)搜索:-user。
    對搜索到的文件執(zhí)行命令:-exec command/batch_file {} \;。{}將替換為搜索到的文件名。\;表示命令結(jié)束。{} +可減少命令運行次數(shù)。
    跳過特定的目錄:find . \( -name ".git" -prune \) -o \( -type f -print \)。

  • 多行輸入轉(zhuǎn)單行輸出:cat example.txt | xargs。
    單行輸入轉(zhuǎn)多行輸出:cat example.txt | xargs -n 3。此處每行3個參數(shù)。
    指定定界符:xargs -d。默認為空格。
    固定格式選項:cat args.txt | xargs -I {} command/batch_file -p {} -l。args.txt中有幾個參數(shù),命令就會執(zhí)行幾次。
    統(tǒng)計目錄中所有 C 程序文件的行數(shù):find . -type f -name "*.c" -print0 | xargs -0 wc -l。必須使用-print0-0,因文件名中可能包含空格。
    對同一參數(shù)執(zhí)行多條命令:cat files.txt | ( while read arg; do cat $arg; done )。

  • ROT13 加密:echo "xxxxxx" | tr 'a-zA-Z' 'n-za-mN-ZA-M'
    刪除字符:cat "Hello 123 World 456" | tr -d '0-9'。
    刪除補集之外的所有字符:echo "a 1 b 2 c 3" | tr -d -c '0-9 \n'
    壓縮重復(fù)字符:tr -s char。
    列數(shù)字求和:cat sum.txt | echo $( tr '\n' '+' ) 0 | bc -l。
    字符類替換:tr '[:lower:]' '[:upper:]'。其余字符類包括alnum/alpha/cntrl/digit/graph/print/punct/space/xdigit。

  • 輸出校驗和到文件:md5sum file1 file2 ... > file_sum.md5
    校驗:md5sum -c *.md5。須與被校驗文件在同一目錄下。
    sha1sum用法同md5sum。二者均為單向散列算法,無法逆推出原始數(shù)據(jù),是存儲密碼的理想方案。但是由于計算能力攀升使其容易破解,推薦使用bcryptsha512sum。
    輸出整個目錄的校驗和:md5deep -rl directory_path > directory.md5,或find directory_path -type f -print0 | xargs -0 md5sum >> directory.md5。

  • crypt加密文件:crypt < input_file > encrypted_file,或直接提供口令crypt PASSPHRASE < input_file > encrypted_file
    解密:crypt PASSPHRASE -d < encrypted_file > output_file。

  • gpg加密文件:gpg -c filename,輸入口令后生成filename.gpg。
    解密:gpg filename.gpg。

  • base64加密:base64 file > output。
    解密:base64 -d output > file。

  • 生成 shadow 密碼字符串:openssl passwd -1 -salt random_string password-1指使用 MD5 基于 BSD 的密鑰算法。

  • 檢查是否已經(jīng)排序:sort -C。
    按第二列的第二個字符至第四個字符排序:sort -k 2.2,2.4
    后接xargs對行做操作時用:sort -z file | xargs -0 command。
    重復(fù)的行僅輸出一次:sort file | uniq。僅輸出不重復(fù)的行:uniq -u。統(tǒng)計出現(xiàn)次數(shù)uniq -c。顯示重復(fù)的行uniq -d。

  • 創(chuàng)建臨時文件:filename=`mktemp`
    創(chuàng)建臨時目錄:dirname=`mktemp -d`。
    生成臨時文件名:tmpfile=`mktemp -u`。
    按模板創(chuàng)建:mktemp tmp_model.xxx。至少3個 xxx。

  • 按大小或行數(shù)等分割文件:split
    按內(nèi)容分割文件:csplit file /SpecificWord/ -n 2 -s {*} -f filename -b "%02d.suffix"。-s為靜默模式。{*}表示重復(fù)進行直到文件結(jié)束;若*為數(shù)字,表示進行分割的次數(shù)。-n指定分割后-f指定的文件名filename后的數(shù)字個數(shù)。-b指定filename后的數(shù)字格式及后綴。

  • 提取文件名和擴展名:

file="sample.jpg"
name=${file%.*}
extension=${file#*.}

%從右向左找最短匹配并刪除,%%找最長匹配并刪除。###則從左向右找。

  • 批量重命名:
#!/bin/bash
# 將當前目錄下的png和jpg文件重命名
count=1
for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1`
do
    new=image-$count.${img##*.}

    echo "Renaming $img to $new"
    mv "$img" "$new"
    let count++
done

C 版本renamerename .JPG .jpg *.JPG,即把所有.JPG文件從.JPG改為.jpg。
Perl 版本renamerename *.JPG *.jpg。所有文件的空格全部替換為下劃線rename 's/ /_/g' *。大寫轉(zhuǎn)小寫rename 'y/A-Z/a-z/' *

  • 精確檢查單詞是否在詞典文件words中:
#!/bin/bash
word=$1
grep "^$1$" /usr/share/dict/words -q
if [ $? -eq 0 ]; then
    echo $word is a dictionary word.
else
    echo $word is not a dictionary word.
fi

其中,^$標記單詞的開始和結(jié)束。-q禁止任何輸出?;蛘?/p>

#!/bin/bash
word=$1
output=`echo \"$word\" | aspell list`
if [ -z $output ]; then
    echo $word is a dictionary word.
else
    echo $word is not a dictionary word.
fi
  • look查詢特定字符串開頭的行:look string filefile必須是經(jīng)過排序的,否則無效。

  • expect可用于實現(xiàn)自動交互,不再手動輸入。

  • 利用多核并行:

#!/bin/bash
PIDARRAY=()
for file in File1.iso File2.iso
do
    md5sum $file &
    PIDARRAY+=("$!")
done
wait ${PIDARRAY[@]}

&將命令置于后臺運行。$!獲得最近一個后臺進程 PID。wait等待進程結(jié)束。

第3章 以文件之名

  • 創(chuàng)建特定大小的文件:dd if=/dev/zero of=junk.data bs=1c/w/b/k/M/G count=1。
    如果bs=2M count=2,則文件大小為 4M。of=一定要仔細檢查。
    dd命令可用于測量內(nèi)存的操作速度。

  • 兩個經(jīng)過排序的文件的比較:comm A.txt B.txt。輸出第一列為只在A.txt中的行,第二列為只在B.txt中的行,第三列為二者共有的行。只打印第三列在末尾加參數(shù)-1 -2。

  • 刪除當前文件夾下的重復(fù)文件:

#!/bin/bash
# ls -lS --time-style=long-iso | awk 'BEGIN {
#     getline; getline
ls -lS --time-style=long-iso | grep ^- | awk 'BEGIN {
    getline
    name1=$8; size=$5
}
{
    name2=$8
    if ( size==$5 )
    {
        "md5sum " name2 | getline; csum2=$1;
        "md5sum " name1 | getline; csum1=$1;
        if ( csum1==csum2 )
        {
            print name1; print name2
        }
    }
    else
    {
        size=$5
    }
   name1=name2
}' | sort -u > duplicate_files
cat duplicate_files | xargs -I {} md5sum {} | sort | uniq -w 32 | awk '{print $2}' | sort -u > duplicate_sample
echo Removing...
comm duplicate_files duplicate_sample -2 -3 | tee /dev/stderr | xargs rm
rm duplicate_files duplicate_sample
echo Removed duplicates files successfully.

若含csum2=$1csum1=$1的兩行交換位置,則運行結(jié)果錯誤,原因不明。

  • setuid 只能用于 Linux ELF 格式二進制文件,不能用于腳本文件。

  • root 用戶可設(shè)置文件不可修改:chattr +i file。任何用戶均可查看lsattr。

  • touch更改文件時間:-a只更改訪問時間,-m只更改修改時間,-d同時更改訪問和修改時間。

  • 顯示符號鏈接指向的路徑:readlink。

  • 統(tǒng)計文件信息:

!/bin/bash
if [ $# -ne 1 ]
then
    echo "Usage is $0 basepath"
    exit
fi
path=$1
declare -A statarray
while read line
do
    ftype=`file -b "$line" | cut -d , -f 1`
    let statarray["$ftype"]++
done < <(find $path -type f -print)
echo ======== File types and counts ========
for ftype in "${!statarray[@]}"
do
    echo $ftype : ${statarray["$ftype"]}
done

其中,$#是傳遞給腳本的參數(shù)個數(shù),$0是腳本自己的名字,$1是傳給腳本的第一個參數(shù),file -b只打印文件類型,cut -d , -f 1選取以逗號分隔的第一列數(shù)據(jù),<(find $path -type f -print)獲取子進程輸出數(shù)據(jù)流。Bash 3.0 及更高版本中,亦可用done <<< "`find $path -type f -print`"。

  • 環(huán)回文件系統(tǒng)的創(chuàng)建和使用:
dd if=/dev/zero of=loopbackfile.img bs=1G count=1
mkfs.ext4 loopbackfile.img
mkdir /mnt/loopback
mount -o loop loopbackfile.img /mnt/loopback
umount /mnt/loopback

分區(qū):

losetup /dev/loop1 loopbackfile.img
fdisk /dev/loop1
losetup -o 32256 /dev/loop2 loopbackfile.img

或使用:

kpartx -v -a loopbackfile.img
mount /dev/mapper/loop0p1 /mnt/loopback1
kpartx -d loopbackfile.img

將對掛載設(shè)備的更改即刻寫入物理設(shè)備:sync。

  • 從光盤創(chuàng)建鏡像:cat /dev/cdrom > image.iso,最好還是用dd if=/dev/cdrom of=image.iso
    從文件創(chuàng)建鏡像:mkisofs -V "Label" -o image.iso source_dir/。
    生成可引導(dǎo)的混合型 ISO:isohybrid image.iso
    刻錄 ISO:cdrecord -v dev=/dev/cdrom image.iso -speed 8。多次刻錄:-multi。
    開關(guān)光驅(qū)托盤:ejecteject -t

  • 生成修補文件:diff -u version1.txt version2.txt > version.patch。
    修補:patch -p1 version1.txt < version.patch。
    撤銷:再執(zhí)行一次上一條命令。

  • 生成目錄的差異信息:diff -Naur directory1 directory2。

  • 打印前 M 行:head -n M file。
    打印除后 M 行之外的所有行:head -n -M file。
    打印后 M 行:tail -n M file
    打印除前 M 行之外的所有行:tail -n +(M+1) file。

  • 關(guān)注文件的變化:tail -f file
    隨進程結(jié)束而結(jié)束關(guān)注:tail -f file --pid $PID。

  • 列出當前目錄下的目錄:ls -d */,ls -F | grep /$ls -ls | grep ^d,find . -type d -maxdepth 1 -print。

  • 命令行中的目錄切換:pushd,在棧中壓入目錄并切換;dirs顯示棧中的目錄;pushd +num,切換到棧中的第num個目錄,從0開始;popd刪除當前目錄并進入切換前的目錄;popd +num刪除指定目錄。

  • 統(tǒng)計行數(shù)、單詞數(shù)、字符數(shù):wc,分別統(tǒng)計wc -l/w/c。打印文件中最長一行的長度wc -L。

  • 以樹狀結(jié)構(gòu)打印文件和目錄:tree PATH。重點標記符合某樣式的文件tree PATH -P PATTERN。重點標記除某樣式外的文件tree PATH -I PATTERN。同時打印文件和目錄的大小tree -h PATH。以 HTML 形式輸出目錄樹tree PATH -H http://localhost -o out.html。

第4章 讓文本飛

  • 正則表達式的基本組成部分:^行首標記,$行尾標記,.匹配任意一個字符,[]匹配包含在方括號內(nèi)的任意一個字符,[^]匹配除方括號內(nèi)的任意一個字符,[-]匹配指定范圍內(nèi)的任意一個字符,?匹配之前的項1次或0次,+匹配之前的項至少1次,*匹配之前的項至少0次,()創(chuàng)建用于匹配的子串,{n}匹配之前的項 n 次,{n,}匹配之前的項至少 n 次,{n,m}匹配之前的項最少 n 次、最多 m 次,|匹配兩邊的任意一項,\將前述特殊字符轉(zhuǎn)義。

  • 著重標記匹配的字符串:grep string filename --color=auto
    使用擴展正則表達式:grep -Eegrep。
    只輸出匹配的文本:egrep -o。
    打印匹配行之外的所有行:grep -v。
    統(tǒng)計匹配行數(shù):grep -c。同一行內(nèi)有多處匹配時,僅算一次。統(tǒng)計匹配的次數(shù)可結(jié)合egrep -owc -l
    打印匹配行的行號:grep -n。
    打印字符串的字符偏移:grep -bo。從整個文本的第一字符算起,起始值為0。
    打印包含匹配字符串的文件:grep -l,不包含的文件grep -L。
    遞歸搜索:grep -R
    忽略大小寫:grep -i。
    多字符串匹配:grep -e string1 -e string2。將每個字符串寫入文件的每一行,根據(jù)文件搜索grep -f。
    指定文件搜索:grep "main()" . -r --include *.{c,cpp}。
    排除文件搜索:grep "main()" . -r --exclude "README"。
    排除目錄:--exclude-dir。
    從文件中讀取排除的文件列表:--exclude-from。
    輸出以0值字節(jié)作為終結(jié)符的文件名:grep -lZ
    靜默輸出:-q。匹配成功返回0,失敗返回非0。
    打印匹配行及其后的 n 行:grep -A n,之前-B n,前后各 n 行-C n。若有多行匹配,以--分隔。

  • 按列打?。?code>cut -f num file,多列num1,num2,num3...。
    排除不含定界符的行:-s。
    打印除某列外的所有行:cut -f num --complement file。
    指定定界符:-d。
    按字符或字節(jié)選?。?code>-c或-b,提取多字段時必須指定輸出定界符cut -c 0-2,4-6 --output-delimiter " "。

  • 打印替換后的文本:sed 's/text/replace/' file。定界符/可任意更換,如,,|,:等等。
    替換并保存:-i,此時不打印;同時保留副本-i.bak。
    全行替換:sed 's/text/replace/g' file。
    全行第 n 處開始替換:sed 's/text/replace/ng' file。
    移除空白行:sed '/^$/d' file
    替換所有的三位數(shù):sed 's/\b[0-9]\{3\}\b/NUMBER/g' file。\b表示字符串邊界。
    所有單詞放入中括號內(nèi):sed 's/\w\+/[&]/g。\w\+匹配每一個單詞,&對應(yīng)匹配字符串。
    大小寫子串互換位置:sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'。
    多個替換:sed 's/a/A/' | sed 's/c/C/'sed 's/a/A/; s/c/C/'sed -e 's/a/A/' -e 's/c/C/'。
    使用變量需要雙引號:sed "s/$text/replace/"。

  • awk基本結(jié)構(gòu):awk 'BEGIN{ commands } pattern { commands } END{ commands }' file。首先執(zhí)行BEGIN語句塊;之后如果滿足pattern的條件則執(zhí)行其后的語句塊,如未提供pattern則默認執(zhí)行,循環(huán)執(zhí)行直到輸入流讀取完畢;最后執(zhí)行END語句塊。
    NR:當前行號。
    NF:當前行的字段數(shù)。
    $0:當前行的文本內(nèi)容。
    傳遞外部變量:awk -v VARIABLE=$VAR,或awk '{ commands }' VARIABLE=$VAR
    BEGIN語句塊中讀取輸入流可以使用getline。
    pattern過濾:NR < 5行號小于5的行,NR==1, NR==5行號在1到5之間的行,/string/包含 string 的行,!/string/不包含 string 的行,/string1/, /string2/包含 string1 的行到包含 string2 的行。
    指定定界符:awk -FBEGIN{ FS=" " },定界符|替換為換行符BEGIN{ RS="|" },換行符替換為定界符BEGIN{ ORS="|" },指定輸出分隔符BEGIN{ OFS="|" }。
    字符串控制函數(shù):length(string)index(string, search_string),split(string, array, delimiter),substr(string, start-position, end-position),sub(regex, replacement_str, string),gsub(regex, replacement_str, string),match(regex, string)

  • 統(tǒng)計詞頻:

#!/bin/bash
if [ $# -ne 1 ]
then
    echo "Usage is $0 filename"
    exit -1
fi
filename=$1
egrep -o "\b[[:alpha:]]+\b" $filename | \
awk '{ count[$0]++ }
END { printf("%-14s%s\n", "Word", "Count");
for( ind in count )
{ printf("%-14s%d\n", ind, count[ind]) }
}'
  • 按列拼接文件:paste,-d指定定界符。

  • 按行逆序打?。?code>tac,-s替換換行符。

awk '{ lifo[NR]=$0 }
END { for ( lno=NR; lno > 0; lno-- ) { print lifo[lno] } }' file
  • 提取電子郵件地址:egrep -o '[A-Za-z0-9._]+@[A-Za-z0-9.]+\.[a-zA-Z]{2,4}'。
    提取 HTTP URL:egrep -o "http://[a-zA-Z0-9.]+\.[a-zA-Z]{2,3}"。

  • 替換變量中的文本:${var/string/replace/}。
    生成變量子串:${var:start_position:length}。

第5章 一團亂麻?沒這回事

  • 下載網(wǎng)頁:wget URL1 URL2 URL3 ...
    下載文件:wget -t 0 ftp://example_domain.com/somefile -O downloaded_file -o log-O重命名,-o將輸出重定向至 log 文件,-t 0不斷重試。
    限速:--limit-rate 20k/m。
    限制最大磁盤配額:--quota-Q
    斷點續(xù)傳:重新下載時使用wget -c。
    復(fù)制網(wǎng)站:wget --mirror --convert-links URL,或wget -r -N -k -l depth URL。
    輸入用戶名和密碼:wget --user username --password pass URL,手動輸入密碼--ask-password。

  • 將網(wǎng)頁內(nèi)容以 ASCII 編碼的形式存儲到文件中:lynx URL -dump > webpage_as_text.txt。

  • 下載數(shù)據(jù)寫入文件:curl URL -o filename --progress。
    斷點續(xù)傳:curl -C - URL。
    從特定的文件偏移處下載:curl URL/file -C offset
    設(shè)置參照頁:curl --referer referer_URL target_URL

第6章 B 計劃

  • 歸檔:tar -cf output.tar file1 file2 file3 ...。
    列出歸檔的文件:tar -tf output.tar,或冗長模式tar -tvf。
    追加文件:tar -rf output.tar new_file。
    提?。?code>tar -xf output.tar,指定目錄tar -xf output.tar -C path。
    提取特定文件:tar -xf output.tar file1 file4。
    打包傳輸:tar -cvf - local_path | ssh user@example.com "tar -xv -C remote_path
    拼接:tar -Af output1.tar output2.tar。
    追加更新的文件:tar -uf output.tar file1,提取時會選最新的。
    判斷歸檔文件與本地同名文件是否相同:tar -df output.tar。
    刪除:tar -f ouput.tar --delete file1 file2
    壓縮:-j zip2 格式,-z gzip 格式,--lzma lzma 格式。
    根據(jù)擴展名自動壓縮:-a。
    歸檔時排除指定文件:tar -cf output.tar * --exclude "*.txt",或根據(jù)文件tar -cf output.tar * -X file。
    排除版本控制相關(guān)的文件和目錄:--exclude-vcs。
    打印總歸檔字節(jié)數(shù):--totals

  • 保留所有文件屬性的歸檔:echo file1 file2 file3 | cpio -ov > archive.iso。
    列出歸檔的內(nèi)容:cpio -it < archive.iso。
    提?。?code>cpio -id < archive.cpio。
    cpio提取至絕對路徑,tar提取至相對路徑。

  • 壓縮:gzip file。
    解壓:gunzip file.gz。
    列出:gzip -l file.gz。
    指定輸出文件:-c >。
    最低壓縮比--fast-1,最高壓縮比--best-9。
    直接讀?。?code>zcat file.gz。
    另有bzip2/bunzip2、lzma/unlzma。

  • 歸檔并壓縮zip,提取unzip不會刪除源文件。
    遞歸-r,更新-u,刪除-d,列出-l。

  • 利用多核歸檔并壓縮:tar -c directory_to_compress | pbzip2 -c > output.tar
    解壓并提?。?code>pbzip2 -dc output.tar | tar -x。
    指定核數(shù):-p。
    指定壓縮比:-1-9

  • 超高的壓縮率,且無須解壓即可讀取少量文件,使用 squashfs 只讀文件系統(tǒng)。
    創(chuàng)建:mksquashfs SOURCES compressedfs.squashfs。
    利用環(huán)回方式掛載:mount -o loop compressedfs.squashfs /mnt/squash。
    創(chuàng)建時排除部分文件:-e,或根據(jù)文件-ef,使用通配符-wildcards。

  • 歸檔并壓縮傳輸:rsync -avz source destination。路徑最后有/和沒有是不同的。
    排除部分文件:--exclude,或根據(jù)文件--exclude-from。
    刪除不存在的文件:--delete

  • 版本控制:
    在備份端的備份目錄中執(zhí)行git init --bare;
    在源端的源目錄中添加編輯者信息git config --global user.name "FirstName FamilyName",git config --global user.email "username@somewhere.com"
    在源目錄中執(zhí)行git init,git commit --allow-empty -am "Init";
    備份git remote add origin user@backuphost:backup_path,git push origin master;
    添加到備份列表git add,從備份列表中刪除git rm
    標注檢查點git commit -m "Commit Message";
    查看所有版本git log;
    恢復(fù)至某版本git checkout ID;
    修復(fù)git clone user@backuphost:backup_path

  • 創(chuàng)建文件系統(tǒng)/分區(qū)備份:fsarchiver savefs backup.fsa /dev/sda1 /dev/sda2。
    恢復(fù)分區(qū):fsarchiver restfs backup.fsa id=0,dest=/dev/sda1 id=1,dest=/dev/sdb1。id=0表示提取第一個分區(qū)的內(nèi)容。

第7章 無網(wǎng)不利

  • MAC 地址欺騙:ifconfig eth0 hw ether new_MAC。重啟后失效。

  • 列出域名的所有 IP 地址:host google.com。
    同時列出 DNS 資源記錄:nslookup google.com

  • 設(shè)置默認網(wǎng)關(guān):route add default gw IP INTERFACE。

  • 查看途經(jīng)的網(wǎng)關(guān):traceroute google.com。

  • 找出網(wǎng)絡(luò)上所有的活動主機:

#!/bin/bash
for ip in 172.17.110.{1..255}
do
(
    ping $ip -c 2 &> /dev/null

    if [ $? -eq 0 ]
    then
        echo $ip is alive.
    fi
)&
done
wait

或者使用fping -a 172.17.110.1/24 -g 2> /dev/nullfping -a 172.17.110.0.1 172.17.110.255 -g。

  • 指定 SSH 端口:ssh user@remotehost -p 422。
    遠程執(zhí)行,本地顯示:ssh user@remotehost 'command1; command2; command3'
    壓縮傳輸:-C。

  • FTP 連接:sftp user@remotehost。上傳put,下載get。
    指定端口:-oPort=PortNumber。

  • scp -p將保留文件的權(quán)限和模式。

  • SSH 自動化認證:
    創(chuàng)建密鑰,指定加密算法為 RSA ssh-keygen -t rsa;
    上傳至遠程主機ssh user@remotehost "cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_rsa.pubssh-copy-id user@remotehost

  • 將本地主機端口8000上的流量轉(zhuǎn)發(fā)到 www.kernel.org 的端口80上:ssh -L 8000:www.kernel.org:80 user@localhost。
    將遠程主機端口8000上的流量轉(zhuǎn)發(fā)到 www.kernel.org 的端口80上:
    ssh -L 8000:www.kernel.org:80 user@REMOTE_MACHINE。
    非交互式:ssh -fL 8000:www.kernel.org:80 user@localhost -N-f執(zhí)行命令前轉(zhuǎn)入后臺,-N說明無需執(zhí)行命令。
    反向端口轉(zhuǎn)發(fā):ssh -R 8000:localhost:80 user@REMOTE_MACHINE。

  • 在本地掛載點上掛載遠程驅(qū)動器:sshfs -o allow_other user@remotehost:remote_path /mnt/mountpoint。

  • 列出開放端口及運行的服務(wù):lsof -inetstat -tnp。

  • 在本地端口 1234 創(chuàng)建套接字nc -l 1234,連接到該套接字nc HOST 1234,可相互發(fā)送信息。
    文件傳輸:在接收端執(zhí)行nc -l 1234 > destination_file,在發(fā)送端執(zhí)行nc HOST 1234 < source_file。

  • 創(chuàng)建無線熱點:

#!/bin/bash
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -A FORWARD -i $1 -o $2 -s 10.99.0.0/16 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A POSTROUTING -t nat -j MASQUERADE

運行./netsharing.sh eth0 wlan0。

  • 阻塞發(fā)送到特定 IP 的流量:iptables -A OUTPUT -d 8.8.8.8 -j DROP。
    阻塞發(fā)送到特定端口的流量:iptables -A OUTPUT -p tcp -dport 21 -j DROP。
    -A添加規(guī)則到OUTPUT規(guī)則鏈中。
    清除所有改動:iptables --flush。

第8章 當個好管家

  • 打印文件或目錄占用的磁盤空間:du。
    打印目錄中每個文件占用的空間:-a。
    默認以字節(jié)為單位,標準容量單位-h。
    指定字節(jié) / KB / MB / 塊為單位:-b/k/m/B。
    打印總計:-c,只打印總計-s
    排除部分文件:--exclude,或根據(jù)文件--exclude-from。
    指定深度:--max-depth。
    排除所有掛載點:-x
    找出大文件:find . -type f -exec du -k {} \; | sort -nrk 1 | head。

  • 磁盤可用空間:df -h。

  • 打印運行時間:time COMMAND
    統(tǒng)計信息寫入文件:/usr/bin/time -o output COMMAND,不覆蓋而是追加至 output -a
    格式化輸出:-f "FORMAT STRING"。real 時間%e,user 時間%U,sys 時間$S。此外還有很多可用參數(shù)。

  • 當前登錄用戶:who,wusers。

  • 查看加電運行時間:uptime。

  • 上一次啟動及登錄信息:last,指定記錄日志-f
    指定用戶:last USER。
    指定會話:last reboot。
    失敗的用戶登錄會話信息:lastb。

  • 統(tǒng)計一小時內(nèi)占用 CPU 最多的十個進程:

#!/bin/bash
SECS=3600
UNIT_TIME=60
STEPS=$(( $SECS / $UNIT_TIME ))
echo Watching CPU usage...
for (( i=0; i<STEPS; i++ ))
do
    ps -eo comm,pcpu | tail -n +2 >> /tmp/cpu_usage.$$
    sleep $UNIT_TIME
done
echo
echo CPU eaters :
cat /tmp/cpu_usage.$$ | \
awk '{process[$1] += $2 }
END{
    for ( i in process )
    {
        printf("%-20s %s\n", i, process[i])
    }
}' | sort -nrk 2 | head
rm /tmp/cpu_usage.$$

comm表示命令名,pcpu表示 CPU 使用率,$$是腳本的進程 ID。

  • 以固定間隔監(jiān)視命令輸出:watch
    指定間隔秒數(shù):-n。默認為兩秒。
    突出差異:-d

  • 監(jiān)視目錄訪問:

#!/bin/bash
path=$1
inotifywait -m -r -e create,move,delete $path -q

持續(xù)監(jiān)視變化-m,遞歸-r,指定需用監(jiān)視的事件-e。

  • logrotate配置文件參數(shù):
    missingok日志文件丟失則忽略,然后返回;
    notifyempty僅當源日志文件非空時才對其進行輪替;
    size限制日志文件的大??;
    compress壓縮舊日志;
    weekly輪替時間間隔;
    rotate保留的舊日志文件的歸檔數(shù)量;
    create 0600 root root指定權(quán)限和屬性。

  • 重要的應(yīng)用程序應(yīng)將執(zhí)行過程記錄在日志文件中。Linux/var/log的重要日志文件包括:
    boot.log系統(tǒng)啟動信息;
    httpdApache Web服務(wù)器日志;
    messages發(fā)布內(nèi)核啟動信息;
    auth.log用戶認證日志;
    dmesg系統(tǒng)啟動信息;
    mail.log郵件服務(wù)器日志;
    Xorg.0.logX 服務(wù)器日志。

  • /var/log/messages中寫入日志信息:logger MESSAGE。特定標記-t。寫入另一日志文件的最后一行-f。

  • 檢測入侵:

#!/bin/bash
AUTHLOG=/var/log/secure
if [[ -n $1 ]];
then
    AUTHLOG=$1
    echo Using Log file : $AUTHLOG
fi
LOG=/tmp/valid.$$.log
grep -v "invalid" $AUTHLOG > $LOG
users=$(grep "Failed password" $LOG | awk '{ print $(NF-5) }' | sort | uniq)
printf "%-5s|%-10s|%-10s|%-13s|%-33s|%s\n" "Sr#" "User" "Attempts" "IP address" "Host_Mapping" "Time range"
ucount=0
ip_list="$(egrep -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" $LOG | sort | uniq)"
for ip in $ip_list
do
    grep $ip $LOG > /tmp/temp.$$.log
    for user in $users
    do
        grep $user /tmp/temp.$$.log > /tmp/$$.log
        cut -c -16 /tmp/$$.log > $$.time
        tstart=$(head -1 $$.time)
        start=$(date -d "$tstart" "+%s")
        tend=$(tail -1 $$.time)
        end=$(date -d "$tend" "+%s")
        limit=$(( $end - $start ))
        if [ $limit -gt 120 ]
        then
            let ucount++
            IP=$(egrep -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" /tmp/$$.log | head -1)
            TIME_RANGE="$tstart-->$tend"
            ATTEMPTS=$(cat /tmp/$$.log | wc -l)
            HOST=$(host $IP | awk '{ print $NF }')
            printf "%-5s|%-10s|%-10s|%-10s|%-33s|%-s\n" "$ucount" "$user" "$ATTEMPTS" "$IP" "$HOST" "$TIME_RANGE"
        fi
    done
done
rm /tmp/valid.$$.log /tmp/$$.log $$.time /tmp/temp.$$.log 2> /dev/null

排除不存在的用戶名grep -v "invalid"。

  • 監(jiān)視遠程磁盤健康狀況:
#!/bin/bash
logfile="diskusage.log"
if [[ -n $1 ]];
then
    logfile=$1
fi
if [ ! -e $logfile ]
then
    printf "%-8s %-14s %-9s %-8s %-6s %-6s %-6s %s\n" "Date" "IP address" "Device" "Capacity" "Used" "Free" "Percent" "Status" > $logfile
fi
ip_list="10.0.0.1 10.0.0.2"
(
for ip in $ip_list
do
    ssh kangk@$ip 'df -H' | grep ^/dev/ > /tmp/$$.df
    while read line
    do
        cur_date=$(date +%D)
        printf "%-8s %-14s " $cur_date $ip
        echo $line | awk '{ printf("%-9s %-8s %-6s %-6s %-8s", $1,$2,$3,$4,$5) }'
        pusg=$(echo $line | egrep -o "[0-9]+%")
        pusg=${pusg/\%/}
        if [ $pusg -lt 80 ]
        then
            echo SAFE
        else
            echo ALERT
        fi
    done < /tmp/$$.df
done
echo
) >> $logfile
  • 電源使用的測量與優(yōu)化:powertop。生成 HTML 格式的報表--html。

  • I/O 監(jiān)視:iotop。只顯示正在進行-o,非交互式打印兩次-b -n 2,特定進程-p `pidof command`

  • 檢查磁盤:fsck。檢查所有/etc/fstab中的-A。自動修復(fù)-a。模擬操作-AN。

第9章 管理重任

  • 列出占用 CPU 最多的10個進程:ps -eo comm,pcpu --sort -pcpu | head。
    指定有效用戶:-u。
    指定真實用戶:-U
    指定 TTY:-t。
    輸出線程相關(guān)信息:-L。
    列出依賴的環(huán)境變量:ps -eo cmd e

  • 列出進程的所有 PID :pgrep command。
    指定定界符:-d。
    指定用戶:-u

  • 列出所有可用的進程信號:kill -l。
    發(fā)送指定信號:kill -s SIGNAL PID。
    常用信號:SIGHUP 1,SIGINT 2,SIGKILL 9,SIGTERM 15,SIGTSTP 20。
    通過命令名:killall
    捕捉并響應(yīng)信號:trap 'signal_handler_function_name' SIGNAL_LIST。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 基礎(chǔ)命令 主要的命令和快捷鍵 Linux系統(tǒng)命令由三部分組成:cmd + [options]+[operation...
    485b1aca799e閱讀 1,233評論 0 0
  • 為何叫做 shell ? shell prompt(PS1) 與 Carriage Return(CR) 的關(guān)系?...
    Zero___閱讀 3,334評論 3 49
  • 1.創(chuàng)建文件夾 !/bin/sh mkdir -m 777 "%%1" 2.創(chuàng)建文件 !/bin/sh touch...
    BigJeffWang閱讀 10,503評論 3 53
  • 《Linux Shell腳本攻略》讀書筆記1 Shell是系統(tǒng)用戶界面,提供用戶與內(nèi)核進行交互操作的一種接口。Sh...
    immiki閱讀 548評論 1 3
  • 你走以后,我絕不想再找,因為麻煩,因為你在我心中無可取代!
    哼哼媽媽閱讀 332評論 0 0

友情鏈接更多精彩內(nèi)容