天天看點

常用shell腳本指令

常用shell腳本指令

1、顯示包含文字aaa的下一行的内容:

sed -n '/aaa/{n;p;}' filename

2、删除目前行與下一行的内容:

sed -i '/aaa/{N;d;}' filename

3、 删除目前行與下兩行的内容:

sed -i '/aaa/{N;N;d;}' filename

依次類推,删除三行,則為{N;N;N;d;},分析知:N為next

4、得出以空格為分割的字元串中單詞的個數,即統計個數:

awk ' { print NF } '

如顯示字元串VALUE中的單詞個數,其中VALUE為:aaa bbb ccc ddd ee f

則執行 echo $VALUE | awk ' { print NF } ' 後的結果為6

5、在linux中建立一個檔案與另一檔案的連結, 即符号連結

ln -s /var/named/chroot/etc/named.conf named.conf

這要就建立了目前目錄的檔案named.conf對/var/named/chroot/etc/named.conf 的符号連結。即操作named.conf就意味着操作實際檔案/var/named/chroot/etc/named.conf ,這時用ll指令檢視的結果如:

lrwxrwxrwx 1 root root 32 Mar 22 12:29 named.conf -> /var/named/chroot/etc/named.conf

注意:當用sed來通過named.conf來删除一部分資訊時,會将符号連結的關系丢掉,即會将named.conf變成一個實際檔案。是以 需對實際檔案進行删除操作。

6、顯示指定字元範圍内的内容:

如:顯示檔案test.txt中字元#test begin與#test end之間所有的字元

sed -n "/#test begin/,/#test end/p" test.txt

或 awk "/#test begin/,/#test end/" test.txt

在日常系統管理工作中,需要編寫腳本來完成特定的功能,編寫shell腳本是一個基本功了!

在編寫的過程中,掌握一些常用的技巧和文法就可 以完成大部分功能了,也就是2/8原則.

1. 單引号和雙引号的差別

單引号與雙引号的最大不同在于雙引号仍然可以引用變量的内容,但單引号内僅是普通字元 ,不會作變量的引用,直接輸出字元竄。請看如下例子:

[[email protected] ~]# name=HaHa

[[email protected] ~]# echo $name

HaHa

[[email protected] ~]# myname="$name is wow"

[[email protected] ~]# echo $myname

HaHa is wow

[[email protected] ~]# myname='$name is wow'

[[email protected] ~]# echo $myname

$name is wow

從上面例子可以看出,使用了單引号的時候,那麼$name隻是普通字元,直接輸出而已!

2. 逐行讀取檔案

• 使用for循環來讀取檔案

for line in `cat file.txt`

do

echo $line

done

注意:由于使用for來讀入檔案裡的行時,會自動把空格和換行符作為一樣分隔符,如果行裡有空格的時候,輸出的結果會很亂,是以 隻适用于行連續不能有空格或者換行符的檔案

• 使用while循環讀取檔案

cat file.txt |while read line

do

echo $line

done

或者:

while read line

do

echo $line

done < file.txt

注意:由于使用while來讀入檔案裡的行時,會整行讀入,不會關注行的内容(空格..),是以比for讀檔案有更好的适用性, 推薦使用while循環讀取檔案

3. bash shell 腳本中常用隐含變量

$0 目前執行的腳本或者指令名稱

$1-$9 代表參數的位置. 舉例 $1 代表第一個參數.

$# 腳本調用的參數的個數

[email protected] 所有參數的内容

$* 所有參數的内容

$$ 目前運作腳本的程序号

$? 指令執行後傳回的狀态

$! 背景運作的最後一個程序号

注意: $? 用于檢查上一個指令執行是否正确(在Linux中,指令退出狀态為0表示該指令正确執行,任何非0值表示指令出錯)

$$ 變量最常見的用途是用做暫存檔案的名字以保證暫存檔案不會重複。

$* 和 [email protected] 如果輸出是一樣的,但是在使用for循環,在使用 雙引号("")引用時 "$*" 會輸出成一個元素 而 "[email protected]" 會按照每個參數是一個元素方式輸出

請看測試例子

#cat test.sh

#!/bin/sh

echo '"[email protected]" output.....'

for i in "[email protected]"

do

echo $i

done

echo '"$*" output ....'

for i in "$*"

do

echo $i

done

輸出結果

#sh test.sh a b c d

"[email protected]" output.....

a

b

c

d

"$*" output ....

a b c d

從輸出結果可以看出 "$*" 輸出是一行 而 "[email protected]" 輸出則是四行

4. 變量内容的删除與替換

我們在一些情況下,需要對變量中的字元竄進行查找删除或者替換,就需要使用下表列出的方法

變量設定方式 說明

${變量#關鍵字} 若變量内容從頭開始的資料符合‘關鍵字’,則将符合的最短資料删除

${變量##關鍵字} 若變量内容從頭開始的資料符合‘關鍵字’,則将符合的最長資料删除

${變量%關鍵字} 若變量内容從尾向前的資料符合‘關鍵字’,則将符合的最短資料删除

${變量%%關鍵字} 若變量内容從尾向前的資料符合‘關鍵字’,則将符合的最長資料删除

${變量/舊字串/新字串} 若變量内容符合‘舊字串’則‘第一個舊字串會被新字串取代

${變量//舊字串/新字串} 若變量内容符合‘舊字串’則‘全部的舊字串會被新字串取代

舉例如下(删除字元竄中的某個字元):

[[email protected] ~]# export test_str="/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"

[[email protected] ~]# echo ${test_str#([^/]*)$,`----1," -e "s,[^/]*/,| ,g"

如何實作取出檔案中特定的列内容

CODE:

[Copy to clipboard]

我們經常會遇 到需要取出分字段的檔案的某些特定字段,例如/etc/password就是通過“:”分隔各個字段的。可以通過cut指令來實作。例如,我們希望将系統 賬号名儲存到特定的檔案,就可以:

  cut -d: -f 1 /etc/passwd >; /tmp/users

  -d用 來定義分隔符,預設為tab鍵,-f表示需要取得哪個字段。

  當然也可以通過cut取得檔案中每行中特定的幾個字元,例如:

  cut -c3-5 /etc/passwd

  就是輸出/etc/passwd檔案中每行的第三到第五個字元。

  -c 和 -f 參數可以跟以下子參數:

  N 第N個字元或字段

  N- 從第一個字元或字段到檔案結束

  N-M 從第N個到第M個字元或字段

  -M 從第一個到第N個字元或字段

在vim中實作批量加密

CODE:

[Copy to clipboard]

密碼中還是不 能帶空格,不管了,能加密就好,先這麼用着。

============================================================

#!/bin/bash

# Encrypt file with vim

if (test $# -lt 2) then

echo Usage: decrypt password filename

else

vim -e -s -c ":set key=$1" -c ':wq' $2

echo "$2 encrypted."

fi

============================================================

[[email protected] weeder]$ for file in *.txt ; do encrypt test $file ; done

test2.txt encrypted.

test4.txt encrypted.

test9.txt encrypted.

kick.txt encrypted.

echo "$2 encrypted."

fi

[[email protected] weeder]$ for file in *.txt ; do encrypt test $file ; done

test2.txt encrypted.

test4.txt encrypted.

test9.txt encrypted.

kick.txt encrypted.

too_old.txt encrypted.

too_old_again.txt encrypted.

bg5.txt encrypted.

[[email protected] weeder]$

[email protected]等特定shell變量的含義

CODE:

[Copy to clipboard]

在shell 腳本的實際編寫中,有一些特殊的變量十分有用:

$# 傳遞到腳本的參數個數

$* 以一個單字元串顯示所有向腳本傳遞的參數。與位置變量不同,此選項參數可超過9個

$$ 腳本運作的目前程序ID号

$! 背景運作的最後一個程序的程序ID号

[email protected] 與$#相同,但是使用時加引号,并在引号中傳回每個參數

$- 顯示shell使用的目前選項,與set指令功能相同

$? 顯示最後指令的退出狀态。0表示沒有錯誤,其他任何值表明有錯誤。

如何使程式的執行結果同時定向到螢幕和檔案

CODE:

[Copy to clipboard]

program_name |tee logfile

這樣程式執行期間的顯示都記錄到logfile同時顯示到标準輸出(螢幕)。

如何用sendmail給系統所有使用者送信

CODE:

[Copy to clipboard]

首先在 aliases檔案裡面建立一個alias:

alluser: :include:/etc/mail/allusers

并執行 newaliases使之生效,然後在/etc/mail/allusers裡面列出所有使用者,可以使用下面的指令:

awk -F: '$3 >; 100 { print $1 }' /etc/passwd >; /etc/mail/allusers

如何查找某條指令的相關庫檔案

CODE:

[Copy to clipboard]

在制作自己的 發行版時經常需要判斷某條指令需要哪些庫檔案的支援,以確定指定的指令在獨立的系統内可以可靠的運作。

在Linux環境下通過ldd指令即可實 現,在控制台執行:

ldd /bin/ls

即可得到/bin/ls指令的相關庫檔案清單。

如何使用host指令獲得更多資訊

CODE:

[Copy to clipboard]

Host能夠 用來查詢域名,然而它可以得到更多的資訊。host -t mx linux.com可以查詢出Linux.com的MX記錄,以及處理Mail的Host的名字。Host -l linux.com會傳回所有注冊在linux.com下的域名。host -a linux.com則會顯示這個主機的所有域名資訊。

如何停止終端多個程序

CODE:

[Copy to clipboard]

以下是腳本:

   echo "系統目前使用者"

  echo "---------------"

  who | awk '{print $2}'

   echo "---------------"

  echo "輸入要殺死終端的終端号:"

  read $TTY

   kill -9 ${K}=`ps -t $TTY | grep [0-9] | awk '{print $1}'`

如何轉存使用者bash_history檔案

# 把以下代碼添加到/etc/profile檔案内

export HISTTIMEFORMAT="%F %T "

USER_IP=`who -u am i 2>/dev/null| awk '{print $NF}'|sed -e 's/[()]//g'`

LOCAL_name=`hostname`

HISTDIR=/var/log/.hist/${LOCAL_name}_`date +%Y%m%d`_auditlog

# 判斷$USER_IP是否為空,如果為空則使用hostname記錄.

if [ -z $USER_IP ]

then

USER_IP=`hostname`

fi

if [ ! -d $HISTDIR ]

then

mkdir -p $HISTDIR

# 為$HISTDIR指派權限,讓所有使用者都可以通路.

chmod 777 $HISTDIR

fi

if [ ! -d $HISTDIR/${LOGNAME} ]

then

mkdir -p $HISTDIR/${LOGNAME}

chmod 300 $HISTDIR/${LOGNAME}

fi

export HISTSIZE=4096

DT=`date +%Y%m%d"_"%T`

export HISTFILE="$HISTDIR/${LOGNAME}/${USER_IP}_${LOGNAME}_$DT"

chmod 600 $HISTDIR/${LOGNAME}/*.hist* 2>/dev/null

2009年04月28日Program, Shell

shell 技巧 腳本

shell常用技巧

用自動導入函數的方法,可以在指令行下像執行指令一樣快捷,而且速度快,占用資源少.

1,建立自己的函數庫

mkdir functionlib

然後将常用的腳本改成函數的文法,如:

function filename { command ; }

将filename拷貝到functionlib中,

2,修改環境檔案,在/etc/profile中添加

export FPATH=$HOME/functionlib

3,重登入一下

這樣的話,你就可以随時用像ls那樣運作你自己的filename”指令”

而不需要用什麼dot,sh,來運作你的函數/腳本啦~~

如果在腳本中運作,可以在腳本頂部用

#!/bin/sh

##

autoload filename //來自動導入函數.

filename //調用函數

用自動導入函數的方法,可以在指令行下像執行指令一樣快捷,而且速度快,占用資源少.

1,建立自己的函數庫

mkdir functionlib

然後将常用的腳本改成函數的文法,如:

function filename { command ; }

将filename拷貝到functionlib中,

2,修改環境檔案,在/etc/profile中添加

export FPATH=$HOME/functionlib

3,重登入一下

這樣的話,你就可以随時用像ls那樣運作你自己的filename”指令”

而不需要用什麼dot,sh,來運作你的函數/腳本啦~~

如果在腳本中運作,可以在腳本頂部用

#!/bin/sh

##

autoload filename //來自動導入函數.

filename //調用函數

技巧:pkill的妙用

——————————————————————————–

有的時候有很多程序或運作或睡眠或僵死,占用了很多寶貴的記憶體空間,kill固然可以殺掉某些程序,但更好的方法是用pkill,舉例:

代碼:

root//root>ps -A

PID TTY TIME CMD

1045 ? 00:00:00 kdeinit

1052 ? 00:00:00 kdeinit

1054 pts/0 00:00:00 xterm

1056 pts/1 00:00:00 bash

1082 pts/0 00:00:00 ps

root//root>free

total used free shared buffers cached

Mem: 252340 212036 40304 0 5752 103200

-/+ buffers/cache: 103084 149256

Swap: 610460 0 610460

root//root>pkill -9 xterm;free

[1]+ Killed xterm

total used free shared buffers cached

Mem: 252340 210776 41564 0 5760 103200

-/+ buffers/cache: 101816 150524

Swap: 610460 0 610460

在我殺掉了xterm這個程序後,看看你的free記憶體空間相應增加不少?.

詳細使用方法請:

man pkill or pkill –help

用stty和dd實作暫停,隻須按一個鍵就可.

#!/bin/ksh

#

function char {

settty=$(stty -g)

stty raw

dd if=/dev/tty bs=1 count=1 2> /dev/null

stty -raw

stty $settty

}

print “Press any key to continue…”

input=$(char)

技巧:如何檢查使用者的輸入?

——————————————————————————–

有的時候,我們對使用者的輸入要作必要的檢測,如,限制輸入的長度/類型.舉例說明:

代碼:

#!/bin/ksh

#要求使用者必須輸入四個數字

while true

do

echo -n “請輸入四個數字:”

read num

len=${#num}

#變量len存放輸入的長度

if [[ $num != [0-9][0-9][0-9][0-9] || $len != 4 ]] then

#進行檢測,如果你輸入有非數字字元,或者長度不等于四個,便提示錯誤資訊

echo “錯誤! 重新輸入”

continue

else

echo “輸入正确,退出!”;exit 0

fi

done

這是個例子,在我們編寫腳本中可以借鑒

shell變量傳遞給sed,awk,grep簡單方法

——————————————————————————–

有時候在腳本編寫中,需要往諸如awk等工具中傳遞shell的變量,舉個簡單的例子,如:

ps -aux|sed -n 1p

read input?”please field number your want to see:”

ps -aux|awk ‘{print $”‘${input}’”}’

read enter?”please line number your want to see:”

ps -aux|sed -n ${enter}p

read user?”please username your want to see:”

ps -aux|grep $user

注:上述檔案無實際意義,隻為說明而已.

開啟小鍵盤數字燈的方法

——————————————————————————–

在man setleds的描述中,有一段設定字元控制台數字燈的腳本:

代碼:

INITTY=/dev/tty[1-8]

for tty in $INITTY

do

setleds -D +num < $tty

done

把它放在/etc/rc.d/rc.local檔案中即可!這樣就可以像WIN一樣一啟動系統,它的小鍵盤的數字燈總是打開的!

在字元模式下,也可以這樣:

setleds -D +num/+caps/+scroll

技巧:把輸入的密碼變成*号的方法

--------------------------------------------------------------------------------

注:此貼轉自:WWW.CHINAUNIX.NET

代碼:

#!/bin/sh

getchar() {

stty cbreak -echo

dd if=/dev/tty bs=1 count=1 2> /dev/null

stty -cbreak echo

}

printf “Please input your passwd: ”

while : ; do

ret=`getchar`

if [ -z $ret ]; then

echo

break

fi

str=”$str$ret”

printf “*”

done

echo “Your password is: $str”

技巧:數值轉換

——————————————————————————–

代碼:

#!/bin/bash

#scriptname:conver

#在BASH下簡單實作十進制到二進制和十六進制的轉換

cat<

技巧:統計文本中單詞數量的方法

——————————————————————————–

有些單詞在一篇文章中經常會出現很多次,怎麼統計這個單詞的個數呢?!

如:檔案kshfile,統計shell這個單詞的個數,

$cat kshfile

ksh

The “Korn” shell, written by David Korn of AT&T Bell Labs (now Lucent). Written as a major upgrade to “sh”, it is compatible with it, but has many more internal commands for the most frequently used functions. It also incorporates most of the same features from tcsh which enhance interactive use (command line history recall etc.). This shell is now available on most systems. It was slow

to gain acceptance because earlier versions were encumbered by AT&T licensing.

$cat kshfile|tr ” ” ” “|grep -wc shell

2

技巧:顯示文本奇數偶數的方法

——————————————————————————–

[javalee//home/javalee/myshell]cat tmp

aaaaaa

dddddd

kasdkfkk

djhasdjf

dfddf

kjsdfklkls

asdfjklkas

#顯示檔案tmp的奇數行的内容:

[javalee//home/javalee/myshell]sed -n ‘1,$p;n’ tmp

aaaaaa

kasdkfkk

dfddf

asdfjklkas

#顯示檔案tmp的偶數行的内容:

[javalee//home/javalee/myshell]sed -n ‘1,$n;p’ tmp

dddddd

djhasdjf

kjsdfklkls

技巧:倒讀文本

——————————————————————————–

例如文章:

$cat -n tmp

1 abcdefgh

2 123234234

3 sjdfk23423

1,行号倒序:

$cat -n tmp|tac #tac和cat很有趣吧~~

3 sjdfk23423

2 123234234

1 abcdefgh

2,每行倒讀:

$cat tmp|rev

hgfedcba

432432321

32432kfdjs

3,全部倒過來:

$cat -n tmp|rev|tac

32432kfdjs 3

432432321 2

hgfedcba 1

4,用sed也可以解決要求對sed有足夠的了解)

$cat -n tmp|sed ‘/ /!G;s/(.)(.* )/&21/;//D;s/.//’

hgfedcba 1

432432321 2

32432kfdjs 3

技巧:把漢字轉換成十六進制和二進制的方法

——————————————————————————–

指令行下,利用perl的unpack函數,可以将漢字巧妙的變成十六進制和二進制,如:

[javalee//home/javalee/myshell]perl -le ‘print unpack(“B*”,”中”);’ #把漢字”中”轉換成二進制

1101011011010000

[javalee//home/javalee/myshell]perl -le ‘print unpack(“H*”,”國”);’ #把漢字”國”轉換成十六進制

b9fa

技巧:妙用watch指令實時觀察記憶體變化

——————————————————————————–

在linux中,有一個很有趣的指令–watch,他的作用很有趣!

他作用是以全螢幕方式重複地執行指定的指令,使用者可以通過他了解指令的運作情況.

如,我們要觀察記憶體動态的變化,那麼就可以:

watch free

這樣就可以動态的觀察記憶體中各個名額在指定時間内的變化啦~~,

如要觀察虛拟記憶體的變化,也可以通過打開另外一個終端,而不耽誤目前終端的操作!:

xterm -e watch -n 1 vmstat &

這樣就會彈出一個xterm,顯示有關虛拟記憶體的情況.

詳細解釋,請:

watch –help

man watch

技巧: 用 tr 過濾檔案[轉貼]

——————————————————————————–

了解文本實用程式

Jacek Artymiak([email protected])

自由作家和顧問

2003 年 7 月

沒有人曾說過 sed 很容易 – 它确實不容易!但通過使用 tr,您可以非常容易地實作 sed 的許多最基本功能。Jacek Artymiak 向您展示如何去做。

您可以将 tr 看作為 sed 的(極其)簡化的變體:它可以用一個字元來替換另一個字元,或者可以完全除去一些字元。您也可以用它來除去重複字元。這就是所有 tr 所能夠做的。

那麼,為什麼要使用 tr,而不使用 sed 呢?當然是為了使事情簡單。例如,如果我們希望用字母”z”來替換出現的所有字母”a”,則可以用 tr a z,這條指令毫無疑問比 sed -e s/a/z/g 簡單,尤其在把它用到腳本中時,其中的引号轉義很讓人頭痛。另外,在使用 tr 時,可以避免寫那些讓人讨厭的正規表達式。

使用 tr 很簡單:使用前面一段中所給出的符号表示法,用一個字元去替換出現的所有另一個字元。當需要替換多個字元時,使用類似于這樣的表示法:tr abc xyz,它表示用字母”x”去替換出現的所有字母”a”,用字母”y”去替換所有字母”b”,用字母”z”去替換所有字母”c”。這兩組中所列出的字元的 數目不必相等。

您也可以指定字元的範圍。例如,tr a-z A-Z 将用對應的大寫字母來替換所有的小寫字母(例如,它将”no smoking”轉換成”NO SMOKING”)。當您在 vi 編輯器中想強調正在編輯的文本的某一部分時,使用這一特殊技巧非常友善。隻要按一下 Escape 鍵,然後按 : 鍵,再輸入 2,4!tr ‘a-z’ ‘A-Z’,最後按一下 Return 鍵。現在,從第 2 行到第 4 行的字母就都轉換成了大寫字母。

關于 tr 的其它内容

GNU 手冊上提到,tr 在執行您所選擇的操作時,通過将标準輸入複制到标準輸出,進而實作”轉換、壓縮和/或删除字元”。在這篇技巧文章中,您将了解到這些選項;當然也可以通過 了解 tr 的手冊頁或資訊頁,學習到更多關于 tr 的内容。

打開一個新的終端視窗,輸入 man tr 或 info tr – 或者打開一個新的浏覽器視窗,并連結到 gnu.org 上的 tr 手冊頁(關于這個連結,請參閱參考資料)。

另外,當有人給您發送了一個在 Mac OS 或 DOS/Windows 機器上建立的文本檔案時,您會發現 tr 非常有用。如果沒有将檔案儲存為使用 UNIX 換行符來表示行結束這種格式,則需要将這樣的檔案轉換成本機 UNIX 格式,否則一些指令實用程式不會正确地處理這些檔案。Mac OS 的行尾以回車字元結束,許多文本處理工具将這樣的檔案作為一行來處理。為了糾正這個問題,可以用下列技巧:

Mac -> UNIX:tr ‘ ‘ ‘ ‘ < macfile > unixfile

UNIX -> Mac:tr ‘ ‘ ‘ ‘ < unixfile > macfile

Microsoft DOS/Windows 約定,文本的每行以回車字元并後跟換行符結束。為了糾正這個問題,可以使用下列指令:

DOS -> UNIX:tr -d ‘ ‘ < dosfile > unixfile

UNIX -> DOS:在這種情況下,需要用 awk,因為 tr 不能插入兩個字元來替換一個字元。要使用的 awk 指令為 awk ‘{ print $0″ ” }’ < unixfile > dosfile

另外,當您需要對文本檔案做一些簡單的整理工作(如用 tr -d ‘ ‘ 除去制表符,用 tr -s ‘ ‘ 除去多餘的空格,或者用 tr -d ‘ ‘ 将分開的幾行合成一行)時,會需要用 tr。同樣,可以在 vi 内使用所有這些指令;隻要記住:在 tr 指令前要加上您希望處理的行範圍和感歎号(!),如 1,$!tr -d ‘ ‘(美元符号表示最後一行)中所示。

技巧:删除檔案中空行的幾種方法

——————————————————————————–

1,cat filename|tr -s ‘ ‘

2,sed ‘/^$/d’ filename

3,awk ‘{if($0!=”")print}’ filename

4,用grep也可以,但是比較麻煩

技巧:如何判斷輸入的是字元還是數字的三個方法

——————————————————————————–

1,用輸入的字元串和任意一個數字進行運算,可以判斷!

代碼:

#!/bin/ksh

#

var=$(echo “$1*1″|bc)

if [[ $var != 0 ]]

then

echo “$1 is a number”

else

echo “$1 is a charter”

fi

2,用流編輯器sed!

代碼:

if [ -n "`echo $1|sed -n '/^[0-9][0-9]*$/p’`” ]

then

echo “$1 is number!”

else

echo “$1 is not number!”

fi

3,用awk來判斷!

代碼:

echo $1|awk ‘{if($0~/[^0-9]/) {print “‘$1′ is not number”} else{print “‘$1′ is number”}}’

技巧:用 uniq 除去重複行[轉]

——————————————————————————–

作者:Jacek Artymiak([email protected])自由作家和顧問 2003 年 7 月

重複行通常不會造成問題,但是有時候它們的确會引起問題。此時,不必花上一個下午的時間來為它們編制過濾器,uniq 指令便是唾手可得的好工具。了解一下它是如何節省您的時間和精力的。

進行排序之後,您會發現有些行是重複的。有時候該重複資訊是不需要的,可以将它除去以節省磁盤空間。不必對文本行進行排序,但是您應當記住 uniq 在讀取行時會對它們進行比較并将隻除去兩個或更多的連續行。下面的示例說明了它實際上是如何工作的:

清單 1. 用 uniq 除去重複行

$ cat happybirthday.txt

Happy Birthday to You!

Happy Birthday to You!

Happy Birthday Dear Tux!

Happy Birthday to You!

$ sort happybirthday.txt

Happy Birthday Dear Tux!

Happy Birthday to You!

Happy Birthday to You!

Happy Birthday to You!

$ sort happybirthday.txt | uniq

Happy Birthday Dear Tux!

Happy Birthday to You!

警告:請不要使用 uniq 或任何其它工具從包含财務或其它重要資料的檔案中除去重複行。在這種情況下,重複行幾乎總是表示同一金額的另一個交易,将它除去會給會計部造成許多困難。 千萬别這麼幹!

有關 uniq 的更多資訊

本系列文章介紹了文本實用程式,它對在手冊頁和資訊頁找到的資訊作了補充。如果您打開新的終端視窗并輸入 man uniq 或 info uniq,或者打開新的浏覽器視窗并檢視位于 gnu.org 的 uniq 手冊頁,那麼就可以了解更多的相關資訊。

如果您希望您的工作輕松點,比如隻顯示唯一的或重複的行,那麼該怎麼辦呢?您可以用 -u(唯一)和 -d(重複)選項來做到這一點,例如:

清單 2. 使用 -u 和 -d 選項

$ sort happybirthday.txt | uniq -u

Happy Birthday Dear Tux!

$ sort happybirthday.txt | uniq -d

Happy Birthday to You!

您還可以用 -c 選項從 uniq 中擷取一些統計資訊:

清單 3. 使用 -c 選項

$ sort happybirthday.txt | uniq -uc

1 Happy Birthday Dear Tux!

$ sort happybirthday.txt | uniq -dc

3 Happy Birthday to You!

就算 uniq 對完整的行進行比較,它仍然會很有用,但是那并非該指令的全部功能。特别友善的是:使用 -f 選項,後面跟着要跳過的字段數,它能夠跳過給定數目的字段。當您檢視系統日志時這非常有用。通常,某些項要被複制許多次,這使得檢視日志很難。使用簡單的 uniq 無法完成任務,因為每一項都以不同的時間戳記開頭。但是如果您告訴它跳過所有的時間字段,您的日志一下子就會變得更加便于管理。試一試 uniq -f 3 /var/log/messages,親眼看看。

還有另一個選項 -s,它的功能就像 -f 一樣,但是跳過給定數目的字元。您可以一起使用 -f 和 -s。uniq 先跳過字段,再跳過字元。如果您隻想使用一些預先設定的字元進行比較,那麼該怎麼辦呢?試試看 -w 選項。

技巧:限時輸入的實作

——————————————————————————–

舉例:

代碼:

#!/bin/ksh

stty -icanon min 0 time 100 <=限定時間為10秒

while

do

echo "Please input:y/m/d/[ENTER]:" <=輸入字母y,m,d或者回車

read input

case $input in

y) date +%Y;break;;

m) date +%m;break;;

d) date +%d;break;;

"") date +%Y/%m/%d;break;; <=當輸入為空(回車)或者10秒鐘内沒有輸入的話,取設定的預設值.

*) echo "wrong!again!";continue;;

esac

done

stty sane

技巧:查找特定字元所在行行号的方法

--------------------------------------------------------------------------------

方法很多,介紹一下3個具有代表性的,

1,grep -n "string" filename

2,sed -n '/string/=' filename

3,awk '/string/{print FNR}' filename

當然,和nl配合使用效果基本一緻!

在shell裡進行算術運算常用的3種方法

--------------------------------------------------------------------------------

1,expr

expr 1 + 2 #注意空格

2,(())

((n=1+2))

3,bc

echo "1+2"|bc #優點可以取小數點的位數

4,

echo $[1+2]

隐藏回顯的另一法

--------------------------------------------------------------------------------

除了用stty -echo來禁止顯示諸如密碼之類的方法外,也可以嘗試這樣

代碼:

echo -n "please input password:�33[8m"

read input

echo -n �33[0m

awk技巧兩則

--------------------------------------------------------------------------------

1,查找一個關鍵詞在整個檔案中出現的次數

代碼:

awk '/keyword/{count++}END{print count }' filename

2,替換

代碼:

awk '{gsub(/oldstr/,"newstr");print}' filename

技巧:從鍵盤輸入生成檔案的若幹方法

--------------------------------------------------------------------------------

1,用echo,如:

代碼:

echo "some strings ">filename

2,用here文檔,如:

代碼:

/home/javalee#cat < filename

>some strings

>!

#CTR+D退出

3,用dd指令,如:

代碼:

/home/javalee#dd filename 2>/dev/null

#CTR+D退出

4,用while循環,如:

代碼:

/home/javalee#while read i;do echo $i >>filename;done

#CTR+D退出

5,用read:如:

代碼:

/home/javalee#while true;do read;echo $REPLY >>filename;[[ -z $REPLY ]]&&break;done

技巧:用grep提取網址/連結的方法

——————————————————————————–

代碼:

grep -o ‘http://[a-zA-Z0-9./?=%_~]*’ urlfile

感興趣的話大家可以測試一下

grep version:

grep (GNU grep) 2.5.1

grep對-o選項的解釋:

-o, –only-matching show only the part of a line matching PATTERN

常用shell腳本的使用

shell, 腳本

我在學習期間寫過一些shell腳本,現在整理出來,希望對剛學習shell的朋友有點用處:

測試過程:vi test.sh 後把程式寫入其中,儲存退出。然後改變檔案屬性:chmod +x test.sh 最後執行:./test.sh

for語句測試:

1)

#!/bin/bash

for num in 1 2 3

do

echo "hello,num=$num"

done

2)

#!/bin/bash

for ((i=1;i<=3;i=i+1 ));do echo hello,$i;done

if語句測試:

#!/bin/bash

echo "please run the program with more than one param"

if [ "$1" = '' ] #$1是隻運作該程式時可加參數1,如./iftest.sh 1 注意等号旁邊和中括号的空格

then

echo "error"

else

echo "ls内容為\n:" #echo '$1':$1

echo `ls`

fi

while語句測試:

1)

#!/bin/bash

m=0

while [ $m -lt 10 ]

do

echo $m

m=`expr $m + 1` #注意m旁邊的空格

done

2)

declare -i m=0 #别一種在算術運算時聲明變量的方法

while [ $m -lt 10 ]

do

echo $m

m=$m+1

done

until語句測試:

1)

#!/bin/bash

declare -i m=10

until [ $m -lt 10 ]

do

echo $m

m=$m-1

done

2)

declare -i m=0

while [ $m -lt 10 ]

do

echo $m

m=$m+1

done

sed測試:

#!/bin/bash

#sed '/^root/ !s/bash/nologin/' /etc/passwd

man sed | col -b > fortest.sh

sed '1,$s/is/--end/' fortest.sh

sed '1,$s/is/--end/g' fortest.sh

sed '/is/=' fortest.sh

引号測試:

#!/bin/bash

var=hello

echo "var is $var"

echo 'var is $var'

echo "var is \$var"

echo `ls`

var2=date

echo `$var2`

case語句測試:

#!/bin/bash

for (( ;; ))

do

echo "please input a key:"

read word

case $word in

1)

echo "your chioce is the one"

;;

2)

echo "your chioce is the two"

;;

3)

echo "your chioce is the three"

;;

q)

echo "your choice is exit"

exit

;;

*)

echo "illegal choice"

exit

esac

done

" $ "符号測試:

#!/bin/bash

echo "please run with more than one parm";

echo "program name \$0:"$0;

echo "first param \$1:"$2;

echo "first param \$$:"$$;

echo "first param \$*:"$*;

數組的使用:

#!/bin/bash

hostip=("100","101","102","103","104","105","106","107","108","109","110")

hostpass=("123456","123456","123456","123456","123456","123456","123456","123456","123456","123456","123456")

i=1

while [ $i -lt 12 ] ; do

ssh [email protected][$i]

done

重新開機别人電腦的shell: #這個好像有點問題,需再測試下

#!/usr/bin/expect

spawn ssh [email protected]

expect "password:"

send "123456\n"

expect "$"

send "reboot\n"

#expect "password:"

#send "123456\n"

expect eof

查找檔案,需指定查找目錄和檔案的修改時間:

#!/bin/bash

path=$1

date=$2

if [ -z $path ]

then

echo "Please input find path:(eg:/dev/abc/)"

read path

fi

if [ -z $date ]

then

echo "Please input find date:(eg:2006-04-23)"

read date

fi

ls -l $path --time-style=long-iso | grep "$date $time"

遞歸算法:

1)

#!/bin/bash

function myls()

{

local y=`ls`;

echo $y;

for z in $y;do

if [ -d $z ];then

echo "進入子目錄";

cd `pwd`/$z;

myls;

echo "傳回上一級目錄";

cd..;

fi

done

}

echo "please input a directory:"

read x

cd $x

myls;

2)#!/bin/bash

check_dir()

{

if [ -d $y ];then

echo "$y是一個目錄";

ls -l $y

else

echo "$y是一個檔案";

fi

}

echo "please input a directory:"

read y

x=`ls $y`

echo $x

for y in $x;do

check_dir

done;

備份腳本:

#!/bin/bash

/bin/tar -zcf /var/mail

/bin/cp /var/mail.tar.gz /root

查找目錄:

#!/bin/bash

ls -l | grep ^d

#輸出目前目錄下的所有目錄

更新ftp伺服器上的檔案:

#!/bin/bash

echo "open 10.0.2.224" > /tmp/ftp1.cmd

echo "user ubunadm 123456" >> /tmp/ftp1.cmd

echo "get `date +%Y`/`date +%Y%m`/`date +%d`/file01 /root/copy/file02" >> /tmp/ftp1.cmd

ftp -nv < /tmp/ftp1.cmd

echo "quit" >> /tmp/ftp1.cmd

echo "open 10.0.2.224" > /tmp/ftp.cmd

echo "user ubunadm 123456" >> /tmp/ftp.cmd

j=`date +%Y`/`date +%Y%m`/`date +%d`

echo "$j"

echo "cd $j" >> /tmp/ftp.cmd

cd /root/copy

m=`ls -l|awk '{print $5}'`

n=$m

while true ; do

echo "大小 $m and $n"

if [ $m -eq $n ] ; then

echo "OK!"

n=$m

echo "**********************************************"

echo "size file01" >> /tmp/ftp.cmd

x=`ftp -nv < /tmp/ftp.cmd`

echo "--------------------------"

echo "檔案内容為:$x"

echo "--------------------------"

m=`echo $x | awk '{print $31}'`

echo "--------------------------"

echo "檔案大小為:$m"

echo "--------------------------"

else

echo "get `date +%Y`/`date +%Y`${x:0:2}/${y:0:2}/file01 /root/copy/file02" >> /tmp/ftp1.cmd

ftp -nv < /tmp/ftp1.cmd

n=$m

echo "更新成功"

fi

sleep 3

done

制作菜單腳本:

1)

#!/bin/bash

x=0

while [ $x -ne 5 ]; do

echo "List Directory......1"

echo "Change Directory....2"

echo "Edit File...........3"

echo "Remove File.........4"

echo "Exit Menu...........5"

echo "Please choose one:"

read x

case $x in

1)echo "current directory is:"

ls `pwd`;;

2)echo "Enter target directory:/"

echo "List Directory......1"

echo "Change Directory....2"

echo "Edit File...........3"

echo "Remove File.........4"

echo "Exit Menu...........5"

echo "Please choose one:"

read y

case $y in

1)echo "current directory is:"

ls `pwd`;;

2)echo "Please a path:"

read z

cd $z;;

3)echo "Please input a file:"

read i

vi $m;;

4)echo "Please input a file";

read j

rm -rf $n;;

5)echo "Exit";;

esac

;;

3)echo "Please input a file:"

read m

vi $m;;

4)echo "Please input a file";

read n

rm -rf $n;;

5)echo "Exit";

esac

done

2)

#!/bin/bash

x=1

while [ $x -ne 0 ]; do

echo "1.ls - list current directory"

echo "2.cd - change directory"

echo "3.mkdir - create a directory"

echo "4.rm - remove"

echo "0.quit"

echo please input:

read x

echo input:$x

case $x in

1)echo "ls - list current directory";;

2)echo "cd - change directory";;

3)echo "mkdir - create a directory";;

4)echo " 1.file - remove a file

2.directory - remove a directory"

read y

echo input is:$y

case $y in

1)echo "file - create a directory";;

2)echo "directory - remove a directory";;

*)echo "bad";;

esac

;;

0)echo "bad";

esac

done

大量發郵件腳本:

1)

#!/bin/bash

exec 3<friends;#将名字,拼音,郵件分成三列輸入friends中

exec 0<&3-;

while read a b c ; do#讀檔案裡的三列

echo $a $b $c;

echo "Hi,$b!

Happy......

...

.... `date`" >mymail#生成一封郵件

mail -S "Happy New Year!" $c < mymail

done

3<&0-

2)

#!/bin/bash

exec 3<friends;#将名字,拼音,郵件分成三列輸入friends中

exec 0<&3-;

while read a b c ; do#讀檔案裡的三列

echo $a $b $c;

mail -S "Happy New Year!" $c <<Delimit

Hi,$b!

Happy......

...

.... `date`"#用臨時文檔( <<Delimit 檔案内容 Delimit )輸入郵件内容

Delimit

done

3<&0-

ssh自動登陸另一台機:

1)

#!/usr/bin/expect

spawn ssh [lindex $argv 0]

set password [lindex $argv 1]

expect "*password:"

send "$password\r"

expect eof

interact #把控制權交給使用者

大批量建立使用者和修改密碼: #此兩腳本為我同學所寫,覺得好就貼出來了

#!/bin/bash

#此腳本适合于ubuntu下

#此小腳本為友善需要批量添加大量使用者的管理者而寫,密碼預設設定為使用者名.

read -p "請輸入你想要添加的使用者名和需要的個數(如:xuanfei 100):" a b

for((i=1;i<=$b;i++))

do

useradd -m $a$i && echo "$a$i:$a$i" > swp && chpasswd < swp && pwconv && echo "添加$a$i使用者成功"

done

rm -rf swp

2)

#!/bin/bash

#此腳本适合于Redhat下

for((i=0;i<10;i++))

do

useradd user$i

echo "加使用者 $user 成功"

echo "user$i" | passwd --stdin user$i

done

一、構造字元串

直接構造

STR_ZERO=hello

STR_FIRST="i am a string"

STR_SECOND='success'

重複多次

#repeat the first parm($1) by $2 times

strRepeat()

{

local x=$2

if [ "$x" == "" ]; then

x=0

fi

local STR_TEMP=""

while [ $x -ge 1 ];

do

STR_TEMP=`printf "%s%s" "$STR_TEMP" "$1"`

x=`expr $x - 1`

done

echo $STR_TEMP

}

舉 例:

STR_REPEAT=`strRepeat "$USER_NAME" 3`

echo "repeat = $STR_REPEAT"

二、指派與拷貝

直接指派

與構造字元串一樣

USER_NAME=terry

從 變量指派

ALIASE_NAME=$USER_NAME

三、聯接

直 接聯接兩個字元串

STR_TEMP=`printf "%s%s" "$STR_ZERO" "$USER_NAME"`

使用 printf可以進行更複雜的聯接

四、求長

求字元數(char)

COUNT_CHAR=`echo "$STR_FIRST" | wc -m`

echo $COUNT_CHAR

求位元組數(byte)

COUNT_BYTE=`echo "$STR_FIRST" | wc -c`

echo $COUNT_BYTE

求字數(word)

COUNT_WORD=`echo "$STR_FIRST" | wc -w`

echo $COUNT_WORD

計算字元串長度可用的三種方法:

echo “$str”|awk '{print length($0)}'

expr length “$str”

echo “$str”|wc -c

但是第三種得出的值會多1,可能是把結束符也計算在内了

判斷字元串為空的方法有三種:

if [ "$str" = "" ]

if [ x"$str" = x ]

if [ -z "$str" ]

注意:都要代雙引号,否則有些指令會報 錯,養成好習慣吧!

五、比較

相等比較

str1 = str2

不 等比較

str1 != str2

舉例:

if [ "$USER_NAME" = "terry" ]; then

echo "I am terry"

fi

小于比較

#return 0 if the two string is equal, return 1 if $1 < $2, else 2strCompare() { local x=0 if [ "$1" != "$2" ]; then x=2 localTEMP=`printf "%s\n%s" "$1" "$2"` local TEMP2=`(echo "$1"; echo "$2") |sort` if [ "$TEMP" = "$TEMP2" ]; then x=1 fi fi echo $x }

六、測試

判空

-z str

判 非空

-n str

是否為數字

# return 0 if the string is num, otherwise 1

strIsNum()

{

local RET=1

if [ -n "$1" ]; then

local STR_TEMP=`echo "$1" | sed 's/[0-9]//g'`

if [ -z "$STR_TEMP" ]; then

RET=0

fi

fi

echo $RET

}

舉例:

if [ -n "$USER_NAME" ]; then

echo "my name is NOT empty"

fi

echo `strIsNum "9980"`

七、分 割

以符号+為準,将字元分割為左右兩部分

使用sed

舉例:

指令 date --rfc-3339 seconds 的輸出為

2007-04-14 15:09:47+08:00

取其+左邊的部分

date --rfc-3339 seconds | sed 's/+[0-9][0-9]:[0-9][0-9]//g'

輸出為

2007-04-14 15:09:47

取+右邊的部分

date --rfc-3339 seconds | sed 's/.*+//g'

輸出為

08:00

以 空格為分割符的字元串分割

使用awk

舉例:

STR_FRUIT="Banana 0.89 100"

取第3字段

echo $STR_FRUIT | awk '{ print $3; }'

八、子字元串

字 符串1是否為字元串2的子字元串

# return 0 is $1 is substring of $2, otherwise 1

strIsSubstring()

{

local x=1

case "$2" in

*$1*) x=0;;

esac

echo $x

}

一、 Linux shell 截取字元變量的前8位,有方法如下:

1.expr substr “$a” 1 8

2.echo $a|awk ‘{print substr(,1,8)}’

3.echo $a|cut -c1-8

4.echo $

5.expr $a : ‘\(.\\).*’

6.echo $a|dd bs=1 count=8 2>/dev/null

二、 按指定的字元串截取

1、第一種方法:

• ${varible##*string} 從左向右截取最後一個string後的字元串

• ${varible#*string}從左向右截取第一個string後的字元串

• ${varible%%string*}從右向左截取最後一個string後的字元串

• ${varible%string*}從右向左截取第一個string後的字元串

“*”隻是一個通配符可以不要

例 子:

$ MYVAR=foodforthought.jpg

$ echo ${MYVAR##*fo}

rthought.jpg

$ echo ${MYVAR#*fo}

odforthought.jpg

2、第二種方法:${varible:n1:n2}:截 取變量varible從n1到n2之間的字元串。

可以根據特定字元偏移和長度,使用另一種形式的變量擴充,來選擇特定子字元串。試着在 bash 中輸入以下行:

$ EXCLAIM=cowabunga

$ echo ${EXCLAIM:0:3}

cow

$ echo ${EXCLAIM:3:7}

abunga

這種形式的字元串截斷非常簡便,隻需用冒号分開來指定起始字元和子字元串 長度。

三、按照指定要求分割:

比如擷取字尾名

ls -al | cut -d “.” -f2

轉載于:https://www.cnblogs.com/sun-frederick/p/4763557.html