返回文章列表

Unix使用者經驗提升指令碼與技巧

本文介紹如何透過 Shell 指令碼提升 Unix 使用者經驗,包含簡化磁碟配額查詢的 `newquota` 指令碼、使 `sftp` 使用更接近 `ftp` 的 `mysftp` 指令碼,以及自訂 `cgrep` 與 `zcat/zmore/zgrep` 指令碼來強化文字搜尋和壓縮檔案處理。此外,文章還提供了一個

系統管理 Shell Script

Unix 系統功能強大,但操作複雜性有時讓使用者卻步。本文介紹的指令碼旨在簡化常見操作,提升使用效率。newquota 指令碼簡化了磁碟配額查詢,mysftp 指令碼則讓 sftp 使用更貼近 ftp。此外,自訂的 cgrep 指令碼強化了 grep 的功能,加入上下文顯示和高亮匹配,而 zcat/zmore/zgrep 指令碼則實作了壓縮檔案的透明處理。最後,bestcompress 指令碼能自動比較多種壓縮工具的效果,選出最佳壓縮方案,進一步最佳化系統資源利用。

提升 Unix 使用者經驗的實用指令碼

Unix 系統在提供強大功能的同時,也常常給使用者帶來一些使用上的困擾。本文將介紹兩個能夠顯著提升使用者經驗的指令碼:newquotamysftp。這兩個指令碼分別用於簡化磁碟配額查詢和使 sftp 的使用體驗更接近傳統的 ftp 客戶端。

簡化磁碟配額查詢:newquota 指令碼

在 Unix 系統中,管理員和使用者經常需要檢查磁碟配額。傳統的 quota 命令雖然功能強大,但其引數選項眾多,使用起來可能稍顯複雜。為此,我們開發了 newquota 指令碼,以簡化磁碟配額的查詢流程。

newquota 指令碼程式碼

#!/bin/bash
# newquota - 簡化磁碟配額查詢

flags=""
while [ $# -gt 0 ]; do
  case "$1" in
    --verbose) flags="$flags -v";;
    --quiet) flags="$flags -q";;
    *) echo "未知引數: $1"; exit 1;;
  esac
  shift
done

exec quota $flags "$@"

內容解密:

  1. while [ $# -gt 0 ]; do 該迴圈遍歷所有傳遞給指令碼的引數,直到所有引數都被處理完畢。
  2. case "$1" in 根據傳遞的引數進行模式匹配,支援 --verbose--quiet 選項,分別對應 quota 命令的 -v-q 選項。
  3. exec quota $flags "$@" 使用 exec 命令替換目前執行的 shell,直接執行 quota 命令並傳遞處理好的引數。這樣做可以節省資源,避免不必要的子 shell。

使用 newquota 指令碼

執行 newquota 指令碼時,使用者可以傳入 --verbose--quiet 引數,分別取得詳細或簡潔的磁碟配額資訊。

$ newquota --verbose
Disk quotas for user dtint (uid 24810):
Filesystem usage quota limit grace files quota limit grace
/usr 338262 614400 675840 10703 120000 126000

$ newquota --quiet

當使用者超出磁碟配額限制時,--quiet 模式下會顯示相關資訊,否則保持靜默。

使 sftp 更像 ftp:mysftp 指令碼

sftpssh 包的一部分,提供了一種安全的檔案傳輸方式。然而,其命令列介面與傳統的 ftp 客戶端有所不同,可能會讓使用者感到困惑。因此,我們開發了 mysftp 指令碼,以使 sftp 的使用體驗更接近 ftp

mysftp 指令碼程式碼

#!/bin/bash
# mysftp - 使 sftp 的使用體驗更像 ftp

/bin/echo -n "User account: "
read account
if [ -z "$account" ]; then
  exit 0
fi

if [ -z "$1" ]; then
  /bin/echo -n "Remote host: "
  read host
  if [ -z "$host" ]; then
    exit 0
  fi
else
  host=$1
fi

exec sftp -C $account@$host

內容解密:

  1. 提示使用者輸入帳號: 使用 /bin/echo -n "User account: "read account 取得使用者帳號。如果使用者直接按 Enter,則離開指令碼。
  2. 處理遠端主機引數: 如果命令列沒有提供遠端主機,則提示使用者輸入;否則,直接使用提供的引數作為遠端主機。
  3. exec sftp -C $account@$host 使用 exec 命令執行 sftp,並啟用壓縮(-C 選項)。這裡直接替換目前的 shell 程式,避免了多餘的子 shell。

使用 mysftp 指令碼

使用 mysftp 時,可以選擇直接輸入遠端主機位址,或在沒有提供主機位址的情況下被提示輸入。

$ mysftp
User account: taylor
Remote host: intuitive.com
Connecting to intuitive.com...
[email protected]'s password:
sftp> quit

$ mysftp intuitive.com
User account: taylor
Connecting to intuitive.com...
[email protected]'s password:
sftp> quit

強化 Unix 工具:自訂 cgrepzcat/zmore/zgrep 指令碼

在 Unix 系統中,經常需要處理文字搜尋和壓縮檔案操作。本文介紹如何透過自訂 shell 指令碼來增強 grep 和壓縮工具的功能,使其更符合實際使用需求。

自訂 cgrep 指令碼:增強 grep 功能

預設的 grep 命令在搜尋文字時,只能顯示匹配的行。透過自訂 cgrep 指令碼,我們可以實作以下增強功能:

  1. 顯示上下文:在匹配的行周圍顯示指定的行數,以便更好地理解匹配內容的上下文。
  2. 高亮匹配內容:使用 ANSI 色彩程式碼高亮顯示匹配的文字,使結果更易閱讀。

實作細節

#!/bin/bash
# cgrep:帶有上下文顯示和匹配高亮的 grep

context=0
esc=$'\033['
boldon="${esc}1m"
boldoff="${esc}22m"
sedscript="/tmp/cgrep.sed.$$"
tempout="/tmp/cgrep.$$"

function showMatches {
    matches=0
    echo "s/$pattern/${boldon}$pattern${boldoff}/g" > $sedscript
    for lineno in $(grep -n "$pattern" $1 | cut -d: -f1); do
        if [ $context -gt 0 ]; then
            prev="$(( $lineno - $context ))"
            [ $prev -lt 1 ] && prev="1"
            next="$(( $lineno + $context ))"
            if [ $matches -gt 0 ]; then
                echo "${prev}i\\" >> $sedscript
                echo "
---
-" >> $sedscript
            fi
            echo "${prev},${next}p" >> $sedscript
        else
            echo "${lineno}p" >> $sedscript
        fi
        matches="$(( $matches + 1 ))"
    done
    if [ $matches -gt 0 ]; then
        sed -n -f $sedscript $1 | uniq | more
    fi
}

trap "rm -f $tempout $sedscript" EXIT

if [ -z "$1" ]; then
    echo "用法: $0 [-c X] 模式 {檔案名}" >&2
    exit 0
fi

if [ "$1" = "-c" ]; then
    context="$2"
    shift; shift
elif [[ "$1" == "-c"* ]]; then
    context="${1#-c}"
    shift
fi

pattern="$1"; shift

if [ $# -gt 0 ]; then
    for filename; do
        echo "
---
-- $filename 
---
--"
        showMatches "$filename"
    done
else
    cat > "$tempout"
    showMatches "$tempout"
fi

exit 0

#### 內容解密:

  1. showMatches 函式:負責生成 sed 指令碼以顯示匹配的行及其上下文,並高亮匹配的文字。

    • 使用 grep -n 取得匹配行的行號。
    • 根據指定的上下文行數,計算出需要顯示的行號範圍。
    • 使用 sed 命令替換匹配的文字,並新增高亮效果。
  2. trap 命令:確保在指令碼離開時刪除臨時檔案,避免留下垃圾檔案。

  3. 引數處理:支援 -c 選項來指定上下文行數,並支援多個檔案或標準輸入。

自訂 zcat/zmore/zgrep 指令碼:透明處理壓縮檔案

在處理壓縮檔案時,通常需要手動解壓後再進行操作。透過自訂 zcat/zmore/zgrep 指令碼,可以實作對壓縮檔案的透明處理,無需手動解壓。

實作細節

#!/bin/bash
# zcat, zmore, 和 zgrep:允許使用者透明地處理壓縮檔案

Z="compress"; unZ="uncompress"; Zlist=""
gz="gzip"; ungz="gunzip"; gzlist=""
bz="bzip2"; unbz="bunzip2"; bzlist=""

for arg; do
    if [ -f "$arg" ]; then
        case "$arg" in
            *.Z) $unZ "$arg"; arg="${arg%.Z}"; Zlist="$Zlist \"$arg\"";;
            *.gz) $ungz "$arg"; arg="${arg%.gz}"; gzlist="$gzlist \"$arg\"";;
            *.bz2) $unbz "$arg"; arg="${arg%.bz2}"; bzlist="$bzlist \"$arg\"";;
        esac
    fi
    newargs="$newargs \"$arg\""
done

case "$(basename "$0")" in
    *zcat*) eval cat $newargs;;
    *zmore*) eval more $newargs;;
    *zgrep*) eval grep $newargs;;
    *) echo "$0: 未知的基礎名稱。無法繼續。" >&2; exit 1;;
esac

if [ -n "$Zlist" ]; then eval $Z $Zlist; fi
if [ -n "$gzlist" ]; then eval $gz $gzlist; fi
if [ -n "$bzlist" ]; then eval $bz $bzlist; fi

exit 0

#### 內容解密:

  1. 遍歷引數:檢查每個引數是否為檔案,並根據檔案的壓縮格式進行解壓和重新命名。

    • 使用 case 陳述式匹配不同的壓縮檔案字尾,並執行相應的解壓命令。
  2. 執行對應命令:根據指令碼的名稱(zcat, zmore, zgrep),執行相應的命令來處理解壓後的檔案。

  3. 重新壓縮:在操作完成後,重新壓縮之前解壓的檔案。

    • 使用 eval 命令確保檔名中的空格被正確處理。

最佳化壓縮檔案的技巧:如何選擇最佳壓縮工具

在 Linux 系統中,有多種壓縮工具可供選擇,但要找到最適合特設定檔案的工具並不容易。本篇文章將探討如何撰寫一個指令碼,以自動測試不同的壓縮工具並選出最佳的壓縮結果。

為什麼需要最佳壓縮工具?

不同的壓縮演算法對不同型別的檔案有不同的壓縮效果。有些檔案可能使用某種壓縮工具可以獲得更好的壓縮率,而其他檔案則可能需要另一種工具。因此,測試多種壓縮工具以找出最適合特設定檔案的工具是十分必要的。

最佳壓縮指令碼(bestcompress)解析

以下是一個名為 bestcompress 的指令碼,它可以自動測試多種壓縮工具並選出最佳的壓縮結果。

指令碼內容

#!/bin/bash
# bestcompress--Given a file, tries compressing it with all the available
# compression tools and keeps the compressed file that's smallest,
# reporting the result to the user. If -a isn't specified, bestcompress
# skips compressed files in the input stream.

Z="compress" gz="gzip" bz="bzip2"
Zout="/tmp/bestcompress.$$.Z"
gzout="/tmp/bestcompress.$$.gz"
bzout="/tmp/bestcompress.$$.bz2"
skipcompressed=1

if [ "$1" = "-a" ] ; then
  skipcompressed=0 ; shift
fi

if [ $# -eq 0 ]; then
  echo "Usage: $0 [-a] file or files to optimally compress" >&2
  exit 1
fi

trap "/bin/rm -f $Zout $gzout $bzout" EXIT

for name in "$@"
do
  if [ ! -f "$name" ] ; then
    echo "$0: file $name not found. Skipped." >&2
    continue
  fi

  if [ "$(echo $name | egrep '(\.Z$|\.gz$|\.bz2$)')" != "" ] ; then
    if [ $skipcompressed -eq 1 ] ; then
      echo "Skipped file ${name}: It's already compressed."
      continue
    else
      echo "Warning: Trying to double-compress $name"
    fi
  fi

  # 同時使用多種壓縮工具進行壓縮
  $Z < "$name" > $Zout &
  $gz < "$name" > $gzout &
  $bz < "$name" > $bzout &
  wait # 等待所有壓縮作業完成

  # 找出最小的壓縮檔案
  smallest="$(ls -l "$name" $Zout $gzout $bzout | \
    awk '{print $5"="NR}' | sort -n | cut -d= -f2 | head -1)"

  case "$smallest" in
    1 ) echo "No space savings by compressing $name. Left as is."
      ;;
    2 ) echo "Best compression is with compress. File renamed ${name}.Z"
      mv $Zout "${name}.Z" ; rm -f "$name"
      ;;
    3 ) echo "Best compression is with gzip. File renamed ${name}.gz"
      mv $gzout "${name}.gz" ; rm -f "$name"
      ;;
    4 ) echo "Best compression is with bzip2. File renamed ${name}.bz2"
      mv $bzout "${name}.bz2" ; rm -f "$name"
      ;;
  esac
done

exit 0

#### 內容解密:

  1. 變數初始化:指令碼首先定義了多種壓縮工具的變數(Zgzbz)以及輸出檔案的名稱。
  2. 引數處理:檢查是否使用了 -a 引數,以決定是否跳過已經壓縮的檔案。
  3. 迴圈處理檔案:對輸入的每個檔案進行檢查,如果檔案不存在或已經被壓縮(且未指定 -a),則跳過該檔案。
  4. 平行壓縮:使用 & 將三種壓縮工具的命令放入後台執行,實作平行壓縮。
  5. 找出最小檔案:透過比較原始檔案和三種壓縮後的檔案大小,找出最小的檔案。
  6. 處理結果:根據最小檔案的來源,輸出相應的訊息,並將最小檔案重新命名為原始檔名加上相應的副檔名。

使用最佳壓縮指令碼

要使用 bestcompress 指令碼,只需將需要壓縮的檔案作為引數傳遞給它即可。如果需要對已經壓縮的檔案進行重新壓縮,可以使用 -a 引數。

範例輸出:

$ ls -l alice.txt
-rw-r--r-- 1 taylor staff 154872 Dec 4 2002 alice.txt

$ bestcompress alice.txt
Best compression is with compress. File renamed alice.txt.Z

$ ls -l alice.txt.Z
-rw-r--r-- 1 taylor wheel 66287 Jul 7 17:31 alice.txt.Z

從上述範例可以看出,bestcompress 指令碼成功地將 alice.txt 檔案壓縮,並選擇了最合適的壓縮工具(在本例中為 compress),最終將檔案大小從 154872 位元組減少到 66287 位元組。