Linux SHELL

    版本為 20:21, 20 Nov 2024

    到這個版本。

    返回到 版本存檔.

    查閱目前版本

    標題索引

     

    天氣氣象

    curl http://v2.wttr.in/taoyuan
    curl http://wttr.in/taoyuan

    numfmt 數字顯示格式化

    $ numfmt --grouping 123456789
    123,456,789
    
    $ numfmt --from=si 2M
    2000000
    $ numfmt --from=iec 2M
    2097152 
    
    $ numfmt --from=iec-i 2Gi  
    2147483648
    
    $ numfmt --to=iec 1000000 
    977K
    

    tr 指令

    去除檔案內的單引號

    tr -d \'
    

    建立暫存檔的方法

    TMPFILE=$(mktemp) || exit 1
    echo "Our temp file is $TMPFILE"
    
    # specify the directory
    TMPFILE=$(mktemp -p /path/to/tmpdir)
    echo "Our temp file is $TMPFILE"
    
    #!/bin/bash
    # Deleting the File After Script Exit
    trap 'rm -f "$TMPFILE"' EXIT
    TMPFILE=$(mktemp)|| exit 1
    echo "Our temp file is $TMPFILE"
    

    監看一個文字檔內容是否有變動

    cat $1 > /tmp/$1.tmp
    while(true)
    do
        if [[ $(diff $1 /tmp/$1.tmp) ]]
            then
                $2
                cat $1 > /tmp/$1.tmp
        fi
        sleep 2
    done
    

    Usage: watchdog.sh log.txt "echo hello"

    有人登入到 root 時自動發通知郵件

    編輯 /root/.bashrc,加上這一行

    echo "ALERT – Root Shell Accessed by `whoami` Login on:" `date` | mail -s "Alert: User `whoami` logged on to `hostname`" user@your.company.com
    

    SHELL 管理

    // 查出目前使用哪種 SHELL

    #> ps -p $$
    #> echo $0
    #> echo $SHELL 
    

    // 執行 SHELL 的方式

    #> sh file
    #> . file
    #> source file
    

    // 在 SHELL 內執行另一個外部 SHELL 或指令
    使用 pipe line

    echo"md5sum $X > $X.sum "| bash
    

    使用 eval

    get_arch="uname -p"
    if [ "`eval "$get_arch"`" = "i686" ]; then
    ....
    fi 

    // 命令模式提示字元的路徑名稱太長
    加上這變數

    PROMPT_DIRTRIM=2

    批次修改密碼

    usernames=$(cat /etc/passwd  | grep bash | sed 's/:.*//g)
    for user in $usernames; do 
        echo "somepassword" | passwd --stdin $user
    done
    

    有些版本不支援 --stdin,可以改用

    usernames=$(cat /etc/passwd  | grep bash | sed 's/:.*//g)
    for user in $usernames; do 
        echo "$user:somepassword" | chpasswd
    done
    

    建立隨機密碼

    cat /dev/urandom | tr -c -d '[:alnum:]' | head -c 16;echo
    

    多個 pipeline 指令

    command1 | command2 | commandN
    
    OR
    
    command1 | filter_data_command > output
    
    OR
    
    get_data_command | verify_data_command | process_data_command | format_data_command > output.data.file
    

    取得每個指令的回應碼

    // 輸出每個指令的回應碼,以 Array 方式
    echo "${PIPESTATUS[@]}"
    
    // 輸入第一個與第二個指令的回應碼
    echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
    

    Command Line 快捷鍵操作

     鍵盤 說明
     Ctrl + a 游標快速移到做前端
     Ctrl + e 游標快速移到最末端
     Alt + f 游標往前移動一段文字
     Alt + b 游標往後移動一段文字
     Ctrl + d 刪除目前游標上的一個字元
     Alt + d 刪除目前游標上的一段文字
     Ctrl + n 下一個歷史指令
     Ctrl + p 上一個歷史指令
     Ctrl + u 裁掉目前游標之前的文字
     Ctrl + k 裁掉目前游標之後的文字

    column 指令

    格式化輸出

    # (printf "DeviceName On MountPoint Type FileSystem\n";mount) | column -t     
    DeviceName                      On  MountPoint                Type  FileSystem
    /dev/mapper/vg_homepbx-lv_root  on  /                         type  ext4         (rw)
    proc                            on  /proc                     type  proc         (rw)
    sysfs                           on  /sys                      type  sysfs        (rw)
    devpts                          on  /dev/pts                  type  devpts       (rw,gid=5,mode=620)
    tmpfs                           on  /dev/shm                  type  tmpfs        (rw)
    /dev/sda1                       on  /boot                     type  ext4         (rw)
    none                            on  /proc/sys/fs/binfmt_misc  type  binfmt_misc  (rw)
    

    install 指令

    快速建立一個目錄且設定好 owner/group,存取權限。

    /usr/bin/install -o www-data -g www-data -m 0755 -d /var/log/freegeoip

    系統資訊 /proc

    CPU:

    cat /proc/cpuinfo
    

    Memory:

    cat /proc/meminfo
    

    OS Version:

    cat /proc/version
    

    陣列 Array

    • 陣列長度:${#str_list[@]}
    • 陣列內容:${str_list[@]}
    #!/bin/bash
    str_list=("aaa" "bbb" "ccc" "ddd")
    echo ${#str_list[@]}
    for i in ${str_list[@]}
    do
      echo "$i"
    done
    
    # Script to split a string based on the delimiter
    my_string="Ubuntu;Linux Mint;Debian;Arch;Fedora"
    IFS=';' read -ra my_array <<< "$my_string"
    
    #Print the split string
    for i in "${my_array[@]}"
    do
        echo $i
    done
    
    # Script to split a string based on the delimiter
    my_string="Ubuntu;Linux Mint;Debian;Arch;Fedora"  
    my_array=($(echo $my_string | tr ";" "\n"))
    
    #Print the split string
    for i in "${my_array[@]}"
    do
        echo $i
    done
    

    mail 指令

    指定 sender name)
    使用 Mutt,適用 CentOS 4

    $ export EMAIL="No Reply<noreply@my.com>"
    $ echo "mail body" | mutt -s "Test Mail" touser@my.com
    

    使用 mailx,適用 AIX 5.3

    $ echo "mail body" | mailx -s "Test mail" -r noreply@my.com touser@my.com
    

    從外部的 SMTP server 轉信)
    使用 mailx 指令

    // 安裝 mailx
    yum install mailx
    
    // 寄信
    $ echo "This is the message body and contains the message" | mailx -v \
    > -r "someone@example.com" \
    > -s "This is the subject" \
    > -S smtp="mail.example.com:587" \
    > -S smtp-use-starttls \
    > -S smtp-auth=login \
    > -S smtp-auth-user="someone@example.com" \
    > -S smtp-auth-password="abc123" \
    > -S ssl-verify=ignore \
    > yourfriend@gmail.com 
    

    TIPs:

    -v 會顯示完整連線訊息,內容類似如下

    Resolving host smtp.gmail.com . . . done.
    Connecting to 74.125.68.109:587 . . . connected.
    220 mx.google.com ESMTP je4sm32812877pbd.94 - gsmtp
    >>> EHLO enlightened
    250-mx.google.com at your service, [122.163.43.21]
    250-SIZE 35882577
    250-8BITMIME
    250-STARTTLS
    250-ENHANCEDSTATUSCODES
    250-PIPELINING
    250-CHUNKING

    SHELL 常用技巧

    // for loop 的應用
    $> for i in var1 var2 var3; do echo $i; done
    $> for ((i=1;i<=10;i++)); do echo $i; done
    $> for i in $(ls *.log); do echo $i; done  
    
    $> for t in {1..10};do  echo $t; done
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    $> for t in {1..10..2};do  echo $t; done
    1
    3
    5
    7
    9
    
    ## 列出目前資料夾的所有目錄名稱
    $> for dir in */;do echo "${dir%/}"; done
    
    ## 讀取檔案內容
    $> cat tables_name.lst | while read sch tab;do
    > echo "export to $tab.ixf of ixf messages export_$tab.msg select * from $sch.$tab"
    > done
    
    // while loop 的應用
    // 每 3 秒監看 /worktmp 的磁碟使用狀況
    $> while true;do
    > df -h | grep /worktmp
    > sleep 3
    > done
    
    // 管理 DB2 時常用
    $> while read s t;do
    > db2 "select count(*) from $s.$t"
    > done < tables.lst > count-tables.out
    
    如果是 CSV
    $> while IFS=, read s t;do
    > db2 "select count(*) from $s.$t"
    > done < tables.csv > count-tables.out
    
    // 大量刪除名稱包含有 /plugins/mactrack 的程式 
    $> ps -ef | grep "/plugins/mactrack" | awk '{system("kill " $2);}'
    
    // 建立臨時檔案或目錄
    TMPFILE=$(mktmp)
    TMPDIR=$(mktmp -d)
    這分別會在 /tmp 目錄建立以亂數取名的臨時檔案或臨時目錄,記得程式最後要將這些臨時檔案目錄移除
    
    // 迴圈計數 Loop Counter
    x=1
    while [ $x -le 5 ]
    do
      echo "Welcome $x times"
      x=$(( $x + 1 )) 或者 x=$[$x + 1]
    done
    

    sort 指令

    sort -t ',' -k5,5 -k1,1 -k9,9 -k3,3 -k11,11 my.csv
    
    •  -t 分隔符號
    • -k5,5 排序第 5 欄,以字串類型排列
    • 欄位排序先後依序為第 5, 1, 9, 3, 11 欄
    • 欄位排序若要以數值方式來排,改成 -k5,5n

    刪除 * 天前的舊備份檔

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    date 指令

    SHELL 寫法

    NOW=`date "+%Y/%m/%d %H:%M:%S"`
    
    eval `date "+day=%d; month=%m; year=%Y"`
    BKNAME="cacti-backup-$year-$month-$day.tar.gz"
    
    NOWD=$(date +"F")   # YYYY-MM-DD
    NOWT=$(date +"%T")  # H:M:S
    

    %T     time; same as %H:%M:%S

    將 Date 轉換為 EPOCH 時間格式
    用 perl 可用於 AIX

    perl -e 'use Time::Local; print timelocal(0,25,1,11,11,2008), "\n";'
    

    常用幾種格式

    # echo `date "+%y-%m-%d_%H%M%S"`
    17-05-22_105503
    
    # echo `date "+%Y/%m/%d"`
    2015/07/17
    
    # echo `date "+%F"`
    2015-07-17
    
    # date --date="49 days ago"
    日  9月 11 16:17:02 CST 2016
    
    # date --date="1 month ago"
    五  9月 30 16:17:34 CST 2016
    

    計算程式執行所花費的時間

    start=`date "+%Y/%m/%d %H:%M:%S"`
    start_s=$(date -d "$start" +%s)
    
    Sleep 20
    
    end=`date "+%Y/%m/%d %H:%M:%S"`
    end_s=$(date -d "$end" +%s)
    diff=$((end_s - start_s))
    

    find 指令

    // 找出大於 1000 MB 的檔案

    find / -type f -size +1000M
    

    // 搬移指定日期範圍的檔案
    將修改日期是 2012 - 2014 的所有檔案搬移至 /export_data/2012-2014。

    touch --date "2012-01-01" /tmp/start
    touch --date "2015-01-01" /tmp/end
    
    find /home/ams/ipdr -type f -newer /tmp/start -not -newer /tmp/end > 2012-2014.lst
    find /home/ams/ipdr -type f -newer /tmp/start -not -newer /tmp/end -exec cp -a {}  /export_data/2012-2014 \;
    find /home/ams/ipdr -type f -newer /tmp/start -not -newer /tmp/end -exec rm -f {} \;
    

    // 列出 2018-03-20 至 2018-04-10 期間曾修改過的檔案

    find ~/ -xdev -newermt 2018-03-20 \! -newermt 2018-04-10 -type f -ls
    

    // 列出 365天以前/20分鐘以前 的所有檔案

    find ./ -ctime +365 -ls
    find ./ -cmin +20 -ls
    

    TIP:

    ctime 檔案建立時間

    mtime 最近檔案修改時間

    atime 最近存取檔案時間

    // 找尋3日內曾異動過的檔案,並轉換 Excel format(csv)

    find . -xdev -mtime -3 -ls > found.list
    sed 's/^[ ]*//g;s/[ ][ ]*/   /g' found.list | awk '{print $3","$5","$6","$7","$8" "$9","$10","$11}' > found.list.csv

    // 列出剛剛異動過的檔案

    最近 5 分鐘異動過的檔案(包含權限與新增檔案)
    find dir -cmin -5
    
    最近 10 分鐘修改過的檔案
    find dir -mmin 10
    

    // 目錄 data 內有許多以日期命名的小 log,需要將去年的所有 log 搬到新目錄 archive-2013
    註:排除目錄 ./archive-2013

    cd data/
    mkdir archive-2013
    find ./ -path "./archive-2013" -prune -o -name "dcdb_13*" -exec mv {} archive-2013 \;
    

    TIPs:

    要排除多個目錄時可以改成
    find ./  \( -path "./dir1" -o -path "./dir2" \) -prune -o -name "dcdb_13*" -exec mv {} archive-XXXX \;

    // 列出最大檔案的清單

    find . -type f -exec wc -c {} \; | sort -nr | head 
    

    // 檔案搜尋結果按時間先後作排序

    find /istrpt/arlog/ -name "*.LOG" -print | xargs ls -lt
    

    計算指定目錄底下的檔案總數量

    用 find

    計算目前目錄底下所有檔案數
    find . -type f | wc -l 
    
    計算第一層所有子目錄的檔案數並排序清單
    find . -maxdepth 1 -type d -print0 | xargs -0 -I {} sh -c 'echo $(find {} -type f | wc -l) {}' | sort -n
    NOTE: 第一層子目錄名稱不可包含空格 
    

    用 rsync 方式計算 /usr 底下檔案數

    rsync --stats --dry-run -ax /usr /tmp
    
    Number of files: 326,373 (reg: 211,698, dir: 24,284, link: 90,391)
    Number of created files: 326,373 (reg: 211,698, dir: 24,284, link: 90,391)
    Number of deleted files: 0
    Number of regular files transferred: 211,698
    Total file size: 7,180,685,730 bytes
    Total transferred file size: 7,178,524,818 bytes
    
    NOTE: 這指令實際不會作檔案複製,/tmp 只是一個假目錄,回傳結果是 reg: 211698 就是檔案總數
    

    用 tree

    tree /mydir -a | tail -n 1
    
    5 directories, 56 files
    
    NOTE: 當目錄底下有包含 symbolic link 也會被計算
    

    輸出多行的文字訊息

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    一次建立或列出多個指定的目錄

    mkdir {AAA,BBB,CCC}
    

    grep 指令

    更多教學:http://www.cyberciti.biz/faq/grep-re...r-expressions/

    // 字串過濾搜尋

    使用 . (period) 表示一個任意字元
    $ grep dev.sda /etc/fstab
    /dev/sda3       /               reiserfs        noatime,ro 1 1
    /dev/sda1       /boot           reiserfs        noauto,noatime,notail 1 2
    /dev/sda2       swap            swap            sw 0 0
    #/dev/sda4      /mnt/extra      reiserfs        noatime,rw 1 1
    
    使用 [ ]
    $ grep dev.sda[12] /etc/fstab
    /dev/sda1       /boot           reiserfs        noauto,noatime,notail 1 2
    /dev/sda2       swap            swap            sw 0 0 
    
    使用 [^12] 表示非1,2字元
    $ grep dev.sda[^12] /etc/fstab
    /dev/sda3       /               reiserfs        noatime,ro 1 1
    #/dev/sda4      /mnt/extra      reiserfs        noatime,rw 1 1
    
    使用正規表示
    $ grep '^#' /etc/fstab
    # /etc/fstab: static file system information.
    #
    $ grep '^#.*\.$' /etc/fstab
    # /etc/fstab: static file system information.
    #
    $ grep 'foo$' filename
    
    搜尋與關鍵字大小寫一致的行
    grep -w "boo" myfile.txt
    
    搜尋包含特殊字元 *** 的關鍵字
    grep '\*\*\*' myfile.txt
    
    更多應用語法
    grep '[vV][iI][Vv][Ee][kK]' filename
    grep '[vV]ivek' filename
    grep -w '[vV]ivek[0-9]' filename
    grep 'foo[0-9][0-9]' filename
    grep '[A-Za-z]' filename
    grep [wn] filename
      
    

    // 搜尋多個關鍵字(使用正規運算式)

    > ls /var/log/ | grep -E "http|secure"
    或
    > ls /var/log/ | grep "http\|secure" 
    

    // 檢查設定檔的參數

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    // 在許多檔案內尋找特定字串內容
    應用:程式碼編寫及除錯

    cd /var/www/html
    grep -r "[搜尋關鍵字]" *
    
    grep -Ril "specific_text" /path/to/dir 
    

    // 搜尋特定字串的文字段落內容
    應用:檢查系統的硬體裝置,以及類似 AIX 的 grep -p

    # lspci -v | awk '/ATI/,/^$/'
    01:03.0 VGA compatible controller: ATI Technologies Inc Rage XL (rev 27) (prog-if 00 [VGA])
            Subsystem: Compaq Computer Corporation: Unknown device 001e
            Flags: bus master, stepping, medium devsel, latency 64
            Memory at fc000000 (32-bit, non-prefetchable) [size=16M]
            I/O ports at 3000 [size=256]
            Memory at fbff0000 (32-bit, non-prefetchable) [size=4K]
            Capabilities: [5c] Power Management version 2

    檔案:grepp.awk
    使用方法:

    #> lspci -v | grepp.awk ATI
    

    列出目錄內最新的 5 個檔案

    Sample#1:

    find . -not -type d -printf "%T+ %p\n" | sort -r | awk '{print $2}' | head -n 5
    ./b01.tar.gz
    ./b02.tar.gz
    ./b03.tar.gz
    ./b04.tar.gz
    ./b05.tar.gz
    

    Sample#2:

    find . -name "*" -type f | xargs ls -lt | head -n 5 | awk '{print $9}'
    ./b11.tar.gz
    ./b10.tar.gz
    ./b09.tar.gz
    ./b08.tar.gz
    ./b07.tar.gz
    

    依照檔案大小排序

    # 從小到大
    ls -l -Sr1 /path-to-dir
    
    # 從大到小 
    ls --sort=size /path-to-dir
    
    # 排序後清單,逐一做壓縮
    ls -Sr1 worktmp/ | while IFS=$'\n' read -r file; do gzip -v9 "$file"; done
    
    # 列出前十大的檔案清單
    du -csk * | sort -rn | head -10
    

    大小寫的轉換

    #轉換成小寫
    toLower() {
       echo $1 | tr "[:upper:]" "[:lower:]"
     } 
    
    #轉換成大寫
    ToUpper() {
       echo $1 | tr "[:lower:]" "[:upper:]"
     }
    

    檢查 MySQL DB 是否存在

    # Checking if DB XXX existed
    # if existed, return 0
    mysql -uroot -p$DBPASS --batch --skip-column-names -e "SHOW DATABASES LIKE '$DBNAME';" | grep $DBNAME > /dev/null; echo $?
    

    test 指令

    (1) 字串或文字的比對

    Str1 == str2 | 當str1與str2相同時, 傳回True
    Str1 != str2| 當str1與str2不同時, 傳回True
    Str1 < Str2 
    Str1 <= Str2
    Str1 > Str2
    Str1 >= Str2
    Str      | 當str不是空字符時, 傳回True
       -n str    | 當str的長度大於0時, 傳回True
       -z str    | 當str的長度是0時, 傳回True
    

    (2) 數字(整數) 比對

    Int1 -eq int2 |當int1等於int2時, 傳回True
    Int1 -ge int2 |當int1大於/等於int2時, 傳回True
    Int1 -le int2 |當int1小於/等於int2時, 傳回True
    Int1 -gt int2 |當int1大於int2時, 傳回True
    Int1 -ne int2 |當int1不等於int2時, 傳回True
    Int1 -lt int2 |當int1小於 int2時, 傳回True 
    

    More Sample Codes:

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    (3) 檔案的比對

    -e file   | 檔案是否存在
    -d file   | 當file是一個目錄時, 傳回 True
    -f file   | 當file是一個普通檔案時, 傳回 True
    -r file   | 當file是一個可讀檔案時, 傳回 True
    -s file   | 當file檔案長度大於0時, 傳回 True
    -w file   | 當file是一個可寫檔案時, 傳回 True
    -x file   | 當file是一個可執行檔案時, 傳回 True
    

    (4) shell的邏輯操作符用於修飾/連接包含整數,字符串,文件操作符的表達式

    ! expr        |當expr的值是False時, 傳回True
    

    更多範例

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    特殊變數及進階應用

    變數 說明
     $0  腳本檔名
     $1  第1個參數
     $2  第2個參數
     ${10}  第10個參數 #10
     $#  參數的個數
     $*  顯示所有參數 (作為一個字串)
     $@  顯示所有參數 (每個為一個獨立字串)
     ${$*}  傳遞到腳本中的參數的個數
     ${$@}  傳遞到腳本中的參數的個數
     $?  腳本結束後的傳回值
     $$  腳本的程序 ID
     $_  前個命令的最後一個參數
     $!  最後一個執行程序的 ID
    u=${1:-root}  如果 $1 未指定,就賦予值 root
    u=${USER:foo}  如果 $USER 未指定,就賦予值 foo;無法用於 $1, $2 變數
    len=${#var}  計算 $var 字串的長度

     

    如果 $2 未指定或空值,輸出錯誤訊息

    ${varName?Error varName is not defined}
    ${varName:?Error varName is not defined or is empty}
    
    MESSAGE="Usage: mkjail.sh domain-name"  ## define error message
    _domain=${2:?"Error: ${MESSAGE}"}              ## you can use $MESSAGE too
    

    ${varable} 進階用法

    https://linuxconfig.org/introduction...ter-expansions

     

    將執行後的所有輸出訊息導入一個檔案

    #!/bin/sh
    LOG="my.log"
    (
    ....
    ) 2>&1 | tee -a $LOG 
    

    TIPs

    不適用在內容裡有 python 指令的訊息輸入,輸入等待的畫面會無法顯示。

    格式化輸出訊息

    • %s 字串
    • %d 整數
    printf "%-40s ..................%s\n" "Disable the service $1" "[$2]"
    
    Disable the service apmd                 ..................[OK]
    Disable the service bluetooth            ..................[OK]
    Disable the service hidd                 ..................[OK]
    Disable the service cups                 ..................[OK]
    Disable the service firstboot            ..................[OK]
    Disable the service readahead_early      ..................[OK]
    
    printf "%40s ..................%s\n" "Disable the service $1" "[$2]"
                    Disable the service apmd ..................[OK]
               Disable the service bluetooth ..................[OK]
                    Disable the service hidd ..................[OK]
                    Disable the service cups ..................[OK]
               Disable the service firstboot ..................[OK]
         Disable the service readahead_early ..................[OK] 

    數值簡單運算

    日期運算

    YEAR=$((YEAR-1))
    MONTH=$((MONTH-1))
    echo "($YEAR + ($YEAR/4) - ($YEAR/100))" 
    

    X的Y次方

    pow() {
        if [ -z "$1" ]; then
            echo "usage: pow <base> <exponent>"
        else
            echo "$1^$2" | bc
        fi
    }
    
    pow2() {
        if [ -z "$1" ]; then
            echo "usage: pow <base> <exponent>"
        else
            echo "$[$1**$2]"
        fi
    }
    
    pow 2 3
    

    去除變數的開頭0

    # $1 is month, $2 is day, $3 is year
    # Strip off leading off zeros from month and day
    MONTH=${1#0}
    DAY=${2#0}
    YEAR=$3
    

    去除變數的末端字元 .XXX

    NAME=${1%.*}
    echo $NAME
    

    更多範例

    Operator "#" means "delete from the left, to the first case of what follows."
        $ x="This is my test string."
        $ echo ${x#* }
    
        is my test string.
    
    Operator "##" means "delete from the left, to the last case of what follows."
        $ x="This is my test string."
        $ echo ${x##* }
    
        string.
    
    Operator "%" means "delete from the right, to the first case of what follows."
        $ x="This is my test string."
        $ echo ${x% *}
    
        This is my test
    
    Operator "%%" means "delete from the right, to the last case of what follows."
        $ x="This is my test string."
        $ echo ${x%% *}
    
        This
    

    比對兩個檔案是否相同

    cmp -s file1 file2
    rc=$? 
    
    • rc=0:兩個一模一樣
    • rc=1:兩個不同檔案
    • rc>1:比對發生錯誤
       

    取得檔案的容量

    #!/bin/bash
    FILENAME=/home/heiko/dummy/packages.txt
    FILESIZE=$(stat -c%s "$FILENAME")
    echo "Size of $FILENAME = $FILESIZE bytes."
    

    取得指定檔案的絕對路徑

    // 指定的檔案
    readlink -f <file.name>
    
    // 目前檔案
    MY_PATH=$(readlink -f "$0") ;目前檔案的絕對路經
    MY_PATH=$( cd $( dirname "$0" ) && pwd ) 
    

    取得目前的檔案名稱

    >echo $0
    ./test.sh
    
    >echo `basename $0`
    test.sh 
    

    expr 指令

    ; 過濾郵件位址的使用者名稱
    ; 列出所有 fax 開頭網域的郵件位址的使用者名稱
    expr "001123@fax.home.net" : '\(.*\)@fax*' 
    

    註:

    \(    \)  等於是 (  ),所包含的就是要輸出內容
    .  任何字元
    .*  不限字數的任何字元
    [^=]  非 = 的字元

    awk 指令

    搜尋字串

    awk '/^this/{print $0}'         ;與 sed -n '/^this/p' 相同
    

    我們經常使用 sort 與 uniq 指令,從檔案中找出並移除重複項目。不過如果你不希望你的原始檔被排序或更動,這時正是 awk 派上用場的時候,我們可以用 awk 截取不重複記錄並儲存在新的檔案中:

    awk '!x[$0]++' filewithdupes > newfile

    搜尋含 disabled 的行,並列出第 1, 3 欄的內容

    awk '/disabled/{print $1, $3}'
    

    取值做計算

    awk '{print "up " $1 /60 " minutes"}' /proc/uptime
    
    df -lP -text4 |awk '{sum += $4} END {printf "%d GiB\n", sum/1048576}'
    df -lP -text4 |awk '{sum += $4} END {printf "%d GiB\n", sum/2**20}'
    

    加上判斷式

    $> df -k |grep "/dev/" | awk '($2 > 0 && ((1 - $3/$2)  > 0.9) ) {print $0 }'
    
    $> awk -F" " '{print ($7 != "A")?$0"***":$0}' myfile

    搜尋每行的第9欄,如果不是 0x00000000 時就顯示該行訊息

    $> cat info.out | awk '($9 != "0x00000000") {print}'
    

    列出 uid >= 500 且 <= 10000 的行

    $> export UGIDLIMIT=500
    $> awk -v LIMIT=$UGIDLIMIT -F: '($3>=LIMIT) && ($3<=10000)' /etc/passwd
    

    解決長整數顯示問題

    $ awk  'BEGIN {print 12345678901234567890}'
    1.23457e+19
    
    方法一
    $ awk  'BEGIN {printf("%d\n", 12345678901234567890)}'
    12345678901234567168
    
    方法二
    $ awk  'BEGIN {OFMT="%.0f"; print 12345678901234567890}'
    12345678901234567168 
    

    列出 uid=0 的帳號

    $> awk -F: '($3 == "0") {print}' /etc/passwd
    

    列出最後一個欄位的值

    ls -ltd */ | awk -F ' ' '{print $NF}'
    

    格式化輸出

    awk '{ printf("1-minute: %s\n5-minute: %s\n15-minute: \
     %s\n",$1,$2,$3); }' /proc/loadavg
    

    計算目錄的檔案大小

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    sed 指令

    ; 列出第 100 行以下的所有文字
    ; 若要刪除,可將 p 換成 d。
    sed -n '100,$p'  my.txt
    
    ; 列出第 3 行以上的所有文字
    sed '3q' my.txt
    
    ; 列出關鍵字 all 以下所有行
    sed -n '/all/,$p' my.txt
    
    ; 搜尋關鍵字,並列出這個段落的所有文字
    sed -n '/keyword/,/^$/p'
    
    ; 列出關鍵字 Top 與 Bottom 之間的所有文字
    sed -n '/Top/,/Bottom/p'
    
     ; 搜尋字串的那一行
    sed -n "/PATTERN/p" my.txt
    
    ; 在第 2 行的上方,插入文字 xxx
    sed '2i xxx' my.txt
    
    ; 在搜尋的行下方新增字串
    sed -e '/patterm/ a\newstring' my.txt
    
    ; 在所有文字的行首加上 #
    sed 's/^/# /' my.txt
    
    ; 在所有文字的行尾加上 End
    sed 's/$/ End/' my.txt
    
    ;刪除行首為# 的行
    sed '/^#/d' 
    
    ; 刪除行首為 # 或空白的行
    sed '/^#\|^$/d'
    
    ;刪除多個關鍵字的行, ADMIN_ERP_ROLE, RPT01,...
    sed '/ADMIN_ERP_ROLE/d;/RPT01/d'
    
    ;刪除空白行
    sed '/^$/d'
    sed '/^\s*$/d'
    
    ;移除行裡的空白與 Tab 字元
    sed 's/^[ \t]*//'
    sed 's/^[ \t]*//;s/[ \t]*$//'
    
    ;將每一行裡是兩個以上空白字元, 都換成一個 comma 符號
    sed "s/  \+/,/g"
    
    ; 刪除空格
    sed 's/[[:space:]]//g' mywords
    
    ; 刪除所有行尾的空格字元
    sed -i 's/[[:space:]]*$//'
    
    ; 刪除行尾的 ^M (CR 字元)
    sed 's/^M//g'      NOTE: to get ^M type CTRL+V followed by CTRL+M
    sed 's/\r$//g'
    
    ; 刪除 iXXXX 的帳號, XXXX 是數字
    sed '/^i[0-9]*/d' mypasswd
    
    ;執行多個規則
    sed -e '/^#/d' -e '/^$/d' 
    
    ;快速取代字串
    sed 's/old/new/' mywords
    sed 's|old|new|' mywords
    
    ; 搜尋關鍵字 'astlogdir =>' 的這一行,取代行字串為 'astlogdir => /mnt/usb/asterisk_log'
    ; .*$ 表示行尾前的所有字串
    sed -i 's/astlogdir =>.*$/astlogdir => \/mnt\/usb\/asterisk_log/g'
    
    ; 搜尋 'none',並且在該行行首加上 '#'
    sed 's/none/#&/g' mywords 
    
    ; 在字串  'daemon' 的下方插入另一個檔案 3.txt 的內容
    sed '/daemon/r 3.txt' mywords 
    
    ; 搜尋文字 'daemon',將符合的內容寫到檔案 3.txt
    sed -n '/daemon/w 3.txt' 1.txt 
    
    ; 將符合文字 'root' 內容的下一行,插入特定的文字 'test test'
    [root@linux-3 ~]# sed ‘/root/a test test’ 1.txt
    root:x:0:0:root:/root:/bin/bash
    test test
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 
    
    ; 將符合文字 'daemon' 內容的上一行,插入特定的文字 'test test'
    [root@linux-3 ~]# sed '/^daemon/i test test' 1.txt
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    test test
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    ; 搜尋所有文字是 'ext3' 的,用 [ ] 框起來
    sed 's/ext3\+/[&]/g' my.txt
    
    ; 搜尋文字並取代部份的內容
    sed -i 's/^\(User\|Group\).*/\1 asterisk/' /etc/httpd/conf/httpd.conf
    

    // 找出關鍵字的右側字串內容

    $ cat cookie.txt
    xxxx  FALSE   /       FALSE   0       PHPSESSID       dbbr5nsmib9tgm0h97sbq8ovd0
    
    $ cat cookie.txt | sed 's/^.*PHPSESSID[ \t]*//' 
    dbbr5nsmib9tgm0h97sbq8ovd0
    

     

    // 對 CSV 檔案的內容,將所有分隔符號 comma 置換成 @@,但必須排除有包含 comma 的文字敘述,這些文字內的 comma 前個字元會有個空白

    sed 's/\(,\)\([^ ]\)/@@\2/g' orig.csv
    

    TIPs:

    s 搜尋

    \( \) \( \) 用括弧區分兩個字元

    [^ ] 非空白的字元

    \2 第二個字元,這裡要配合括弧的用法

    g 作全文置換,若沒有此參數,預設只會置換第一個符合的字元

    // 搜尋 A.AA B.BB C.CC 3個數值,並以指定的格式輸出

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)

    TIPs:

    ^\([0-9]\+\.[0-9]\+\) \([0-9]\+\.[0-9]\+\) \([0-9]\+\.[0-9]\+\).*$  搜尋語法
    1-minute: \1\n5-minute: \2\n15-minute: \3 輸出語法

    // 取代所有的 mailbox = xxx 為 mailbox = xxx@context

    sed 's/^mailbox = [0-9]*/&@context/g' users.conf
    

    // 搜尋特定區段的 AllowOverride None
    只取代這個區段所包含的關鍵字

    <Directory "/var/www/html">
    ...

    <Directory>

    sed -i ':a;N;$!ba;s/AllowOverride None/AllowOverride All/2' /etc/httpd/conf/httpd.conf
    

    // 擷取 { } 所包含的所有文字

    <br/> <b>Notice</b>: Undefined variable: sn in <b>/var/www/raida/service/fix.php</b> on line <b>259</b><br/> {"server":"RAIDA17","sn":"","status":"success","message":"Fixed: Unit's AN was changed to the PAN. Update your AN to the new PAN.","time":"2017-04-08 06:08:25"}

    echo $( cat http_get.txt ) | sed  's/.* \({.*}\)$/\1/'
    

    // 擷取 [ ] 內的文字

    echo "[1070059:1,1070060:1,1070039:1]" | sed  's/^\[\(.*\)\]$/\1/'
    

    列出某個執行中的 process 會開啟的相關檔案列表

    lsof -p `pidof <app_name>`
    

    隱藏/消除文字檔內以#或;符號開頭的每一行

    grep -Ev "^(#|;)" example.txt
    

    延伸應用:
    自動刪除文字檔內所記載的目錄及檔案,例如:

    # file: remove.list
    # please remove this directory and files below
    /path/to/file.1
    /path/to/file.2
    /path/to/dir/
    /path/to/dir-1/
    

    依照檔案清單做連續刪除的指令行:

    grep -Ev "^(#|;)" remove.list | xargs -n 1 ls -l
    grep -Ev "^(#|;)" remove.list | xargs -n 1 rm -rf 
    

    快速修改大量檔案的副檔名

    ## *.old -> *.new
    for fname in $(ls *.old);do echo "mv $fname ->"; echo $(echo $fname |sed 's/.old/.new/');mv $fname $(echo $fname | sed 's/.old/.new/');done
    

    如何取得 process ID

    for SHELL process:

    #!/bin/bash
    #
    /path/to/my/shell.sh &
    echo $PPID
    
    # pidof <app_name>
    
    #!/bin/bash
    echo $$ 
    

    for java process:

    #!/bin/bash
    #
    /path/to/java myjava.jar &
    echo $!
    

    取得目前 IP address

    internip=`ifconfig | grep -m 2 ^ | cut -f 2 -d ":" | cut -f 1 -d " " | tail -1`
    privnet="${internip%.*}.0/255.255.255.0"
    echo $internip 
    echo $privnet
    

    取得目前所有的網路裝置名稱

    #!/bin/bash
    
    devs=`ip -o link | cut -f 2 --delimiter=' ' -`
    echo "devs="$devs
    
    for i in $devs; do
        dev_name=$(echo ${i%:})
        ip=$(ifconfig $d) && ip=${ip#*inet addr:} && ip=${ip%% *}
        echo "Device Name: "$dev_name
        echo "Device IP: "$ip
        echo "-------------"
    done
    

    auto-rar.sh

    reference to undefined name 'syntax' Exception of type 'MindTouch.Deki.Script.Runtime.DekiScriptUndefinedNameException' was thrown. (click for details)
    Powered by MindTouch Core