Learning Shell Scripting

版主: stnet253

回覆文章
admin
系統管理員
文章: 36
註冊時間: 2012-02-25, 22:10
聯繫:

Learning Shell Scripting

未閱讀文章 admin »

前言
Shell Script主要用途就是用來協助使用者在UNIX or Linux環境上, 以更方便, 更自動化的方式來執行想要執行的指令, 它也可以很快速的協助使用者 or 管理者大量地執行重複性的動作與指令. 做為一個系統管理者, 學會Shell Script絕對可以事半功倍.

底下的教學與心得分享是假設你已經有著基本的UNIX or Linux觀念與技巧, 同時我們利用Linux預設提供的bash shell來操作, 例如 :
UNIX/Linux 操作環境, 已經了解使用者登出入的流程
基本的指令操作, 例如 ls, cd, mkdir..etc)
使用 vi 或其他編輯器
了解基本流程判斷與控制, 例如if-then-else與while, for迴圈
此外, 這邊還有提供一些 Shell Scripting FAQ 與幾個 Shell Script samples , 希望對讀者有幫助

如果你覺得這些資訊對你有幫助, 也請幫忙點選網頁上的廣告, 感謝.




基本觀念與操作
開始建立第一個shell script
$ pwd
/home/xfish/bin

$ ls
myscript
myscript2

$ cat myscript
ls -aF

$ myscript
bash: ./myscript: Permission denied

$ chmod +x myscript

$ ./myscript
./ ../ myscript* myscript2*

shell script其實就是一個很簡單的文字檔案, 檔案裡面有著可以操作與控制相關動作與命令, 同時它必須具備能夠執行的能力,
在UNIX與Linux環境下, 也就是必須有 +x 的屬性

上面是一個很簡單的shell script, 簡單地列出目前目錄下的檔案.

同時由於Linux/UNIX底下有多種shell的編譯器, 我們也可以在該script中的第一行來指定利用特定的編譯器執行,
例如我們可以指定 : #!/bin/bash

而有時候因為需要偵錯(debug), 我們也會利用以下的方式執行 shell script :

$ sh -x ./myscript

或者直接於第一行的 #!/bin/bash 該改為 #!/bin/bash -x , 執行的效果會類似這樣:

$ ./myscript
+ ls -aF (這一行是多出來的, 代表當時shell script執行到這一行)
./ ../ myscript* myscript2
使用echo命令
echo是用來顯示輸出的命令, 用幾個範例做個解釋, 後面的章節
將會看到常常利用echo來做些輸出的動作 :

$ echo a b c
a b c
$ echo "a b c"
a b c
$ echo $0
-bash (說明, 這個會依照你使用的shell不同而改變)

同時echo還能搭配以下特殊符號來控制特別輸出 :

\a alert, beeps the bell
\b backspace character
\c suppresses the new line
\f formfeed character
\n new-line
\r return character
\t tab character
\v vertical tab character
\\ single backslash character

以下是常用的 echo 範例:

利用 echo 顯示文字:
$ echo "Hello World"

利用 echo 顯示執行動作與結果 (在進行大量批次動作常用) :

echo -n "process $file now ...."
myprog $file > /dev/null
if [ $? -eq 0 ]; then
echo "OK"
else
echo "Failed"
fi

利用 echo -n 將游標保留在與 process $file now ... 同一行, 接著根據 myprog $file 的結果, 顯示 OK 或者 Failed,
這樣的效果會變成 :

process xxxx now ....OK 或者 process xxxx now ....Failed





起始檔案 startup files
跟以往的DOS相同, 使用者登入後, 系統的shell在讀取完系統的設定檔後(/etc/profile), 會自動讀取使用者shell,
例如 : $HOME/.bashrc 或者 $HOME/.profile 或甚至 $HOME/.bash_profile (請參考Linux的基本操作)

因此, 若有一些需要使用者登入後就執行或者設定的動作, 可以在這兩個檔案作設定的起始檔案
命令區隔
若有同時兩個命令要執行, 必須使用 ; 來區隔

$ date who (錯誤)
date: bad conversion

$ date ; who (正確)
Tue Aug 25 15:38:24 2005
xfish tty00 Aug 25 15:30
root ttyp1 Aug 25 10:00

$ cd bin ; pwd
/home/xfish/bin

$ cd .. ; pwd
/home/xfish
Grouping 命令
利用( ) 來整合命令, 例如 :

$ pwd
/home/xfish

$ ( cd /bin ; pwd )
/bin

$ pwd
/home/xfish

$ ls -l /usr/bin ; ls -l /usr/share | wc -l
這樣會列出 /usr/bin 與/usr/share 目錄下的檔案, 但是事實上我們只要算算這總共有多少命令, 因此我們可以利用下面的命令取代 :

$ (ls -l /usr/bin ; ls -l /usr/share ) | wc -l
185

Shell Script 概論
這一章, 我們會談到包括一些使用shell script的基本方法, 主要會提到 :
Aliases 別名
Here Documents 可以說是一種內嵌的文件
Job Control 工作控制
Aliases 別名
直接在命令提示符號下 : alias 命令 , 你就可以看到目前定義的 alias.
而alias就是常常用來把一大串命令縮寫的常用技巧.

比如說我喜歡ls的時候加上ls -F選項, 同時我希望打ls時候預設就帶入 -F 參數, 就可以利用 :

$ alias ls='ls -F' 來達到你的目的

多看幾個例子 :

$ alias lf="/usr/bin/ls -CaF"

$ alias rm=echo

$ rm /tmp/junk
/tmp/junk

Here Documents
一種內嵌於shell script的技巧, 直接用例子說明 :

$ cat phone
#!/bin/bash
grep -i $1 << END
A Company 404 123 5888
Rosebery Corp. 314 713 7639
Chedworth.com 212 987 6543
Atlanta.Net 770 111 2222
END

$ phone atla
Atlanta.Net 770 111 2222 (這是輸出結果)

另外, END 那個只是一個識別, 也就是說, 你可以用其他字元代替,不過還是建議用單字或者字串做為識別, 而不要用符號

Job Control 工作控制
工作流程控制, 大概有幾個命令一定得先了解, 包括了 :
jobs [-lp] [job]
bg [job..]
fg [job..]
kill [-signal] job..
wait [job..]
同時上述的 [job] 可以用這樣的方式來表示 :
%number : refer to job by number
%string : job whose name begins with string
%?string : job whose name contains string
%+ or %% : current job
%- : previous job
所以希望參考完這個例子, 你就能對Job Control工作流程控制有些了解.

$ stty susp ^Z (確保 susp 是 ^Z (Ctrl + Z))

$ stty tostop

$ ls -R / (這個命令可以讓系統跑很久, 按下 Ctrl + Z)
^Z
[1]+ Stopped ls -R / (系統提示這個編號 1 的 job 被 stopped)

$ bg (執行 bg 命令, 把編號 1 丟到後端去跑)
[1]+ ls -R / &

$ (sleep 36 ; echo Hello World) & (執行第二道命令)
[2] 656 (系統給編號 2 的命令)
[1]+ Stopped ls -R /

$ jobs (利用 jobs 命令 查看所有後端工作)
[1]- Stopped ls -R /
[2]+ Stopped (sleep 36;echo Hello World)

$ kill %- (刪除前一編號的工作)
[1]- Stopped ls -R /

$ jobs (利用 jobs 命令 再次查看所有後端工作)
[1]- Terminated ls -R /
[2]+ Stopped (sleep 36; echo Hello World)

$ fg %2 (把編號 2 命令帶到 前端 )
(sleep 36; echo Hello World)
Hello World (列印出 結果 並結束 )





變數定義
變數在shell script裡面扮演很重要的腳色, 會寫程式的都應該知道 變數的定義, 其重要性, 也不用我多說, 我們這邊會包括以下幾部分 :
變數的定義
保留/系統預設的變數
變數的定義
還是直接用例子來說明, 最容易了解. 底下這些都是變數定義的方式(在/bin/bash或者/bin/sh環境下) :

$ name=Derek
$ fullname='Derek Super'
$ completename="Derek Super Man"

$ echo my name is $name, $fullname, $completename
my name is Derek, Derek Super, Derek Super Man

$ question='What is "sheckle"'
$ echo my question is $question
my question is What is "sheckle"

保留/系統預設的變數
系統預設已經有相當多的變數定義了, 因此在你的shell script裡面 要去避免這些變數. 以下就是一些預設的系統變數.

$BASH_ENV absolute path of startup file
$CDPATH directories searched by cd
$FCEDIT absolute path of history editor
$HISTCMD the history number of the current command
$HISFILE absolute path of history file
$HISTSIZE number of remembered commands
$HOME login directory
$IFS token delimiters
$LINENO current line number in shell script
$LINES terminal height
$MAIL absolute path of mailbox
$MAILCHECK number of seconds to check mail
$OLDPWD absolute path of previous directory
$OPTARG option set by getopt
$OPTIND option's ordinal position set by getopt
$OSTYPE the OS on which bash is executing
$PATH command search path
$PPID process ID of parent
$PS1 primary prompt
$PS2 secondary prompt
$PWD absolute path of current directory
$RANDOM random integer
$REPLY default variable for read
$SECONDS number of seconds since shell started
$SHELL absolute pathname of preferred shell
$TMOUT seconds to log out after lack of use
$UID user ID of the current user
$$ process ID of current shell
$? exit status of most recent statement
$# 參數的數目
$* 代表所有參數
$! PID of the most recently started backgroup job


另外, 還有參數的傳遞也需要了解, 例如當我們編寫一個 script 內容如下:

#!/bin/bash
echo "\$0 ==> $0"
echo "\$1 ==> $1"
echo "\$2 ==> $2"

則執行以下命令的時候:

./myscript Hello World
$0 ==> ./myscript
$1 ==> Hello
$2 ==> World
shell的判斷式
從這邊開始, 我們將開始進入一些shell script的判斷, 就是說我們會利用到if-then-else的一些判斷, 來讓shell script具備判斷能力.

討論的主題預計包括 :
if-then-else 敘述
testing 判斷式
case 敘述
if-then-else
先用一個簡單的例子, 來敘述If-Then-Else敘述.

$ cat myscript5
#!/bin/sh
if grep $1 /etc/passwd
then
echo "FOUND !!!!"
fi

$ ./myscript5 xfish
xfish:x:200:200:Xfish:/home/xfish:/bin/bash
FOUND !!!!

$ ./myscript5 ABCdefga

說明 :
myscript5 將會對/etc/passwd檔案 進行尋找, 若找到參數所指定的字串, 就印出 FOUND !!!!

因為我們/etc/passwd有xfish這個帳號, 因此 第一個命令會找到該字串, 並印出 FOUND !!!!

所以 由於我們/etc/passwd並沒有ABCdefga字串, 因此直接結束程式. 沒有印出任何訊息.

但是如果我們只想要 在有找到我指定的字串時, 簡單的輸出 FOUND !!!!
不要把 grep 命令的 output 印出來, 同時加上一些變數, 讓輸出更多樣化, 我們可以把 myscript5 再修改成 :

$ cat myscript5
#!/bin/sh
if grep $1 /etc/passwd > /dev/null
then
echo "found $1"
else
echo "didn't find $1"
fi

$ ./myscript5 xfish
found xfish

$ ./myscript5 ABAaa
didn't find ABAaa

那如果多重式的if-then-else要怎麼寫呢? 我們再以剛剛的例子來變化.

$ cat myscript6
#!/bin/sh
if grep $1 /etc/passwd > /dev/null; then
echo "found $1 in /etc/passwd"
elif grep $1 /etc/greoup > /dev/null; then
echo "found $1 in /etc/group"
else
echo "didn't find $1"
fi

$ myscript6 other
found other in /etc/group

$ myscript6 AabcdB
didn't find AabcdB

以下也是一個常用的範例, 例如我們可以根據定義的參數, 進行更多訊息的顯示:

if [ $DEBUG -eq 1 ]; then
echo "display debug level 1 info"
elif [ $DEBUG -eq 2 ]; then
echo "display debug level 2 info"
elif [ $DEBUG -eq 3 ]; then
echo "display debug level 3 info"
else
echo "you don't define any debug level, display ooxx..."
fi
testing 判斷式
testing 判斷式通常與if-then-else一起互用, 以便發揮其效果. 先從一個最簡單的例子看起 :

$ cat myscript7
#!/bin/sh
if [ -f /etc/passwd ]; then
echo "/etc/passwd is a file"
else
echo "PANIC : /etc/passwd is not a file!!"
fi

先說明一下 [ -f /etc/passwd ] 這個最重要的部份, [ ] 裡面就是判斷式, 而這裡是判斷 /etc/passwd 是不是一個 file ?
由結果來看看是執行 then 下面的敘述, 或者執行 else 的敘述.

同時很重要一點是 底下這些敘述都是不正確的敘述, 會有錯誤產生喔 :

[-f /etc/passwd ] [-f 連在一起
[ -f /etc/passwd] passwd] 連在一起
[ -f/etc/passwd ] -f與/etc/passwd連在一起

這裡是一個雙重條件判斷的範例:

CONFIG=config.ini
if [ -e $CONFIG -a "`grep ^Mailer $CONFIG`" ]; then
SERVER_LIST=(`grep ^Mailer $CONFIG | cut -d= -f2 | sed 's/,/ /g'`)
SERVER_NUM=${#SERVER_LIST[@]}
else
echo "$CONFIG not found"
exit 2
fi

上述的範例有些複雜, 簡單的說它透過 -a (代表 and) 判斷是否同時滿足 -e $CONFIG 與 `grep ^Mailer $CONFIG?
所以另外一個 -o (寄是代表 or) 就會類似這樣了:

if [ -e $CONFIG -o "`grep ^Mailer $CONFIG`" ]; then
XXXXX (自己發揮)
fi

所以利用 [ ] 我們可以做出以下這些判斷, 這些也都很常用喔 !!

[ string1 = string2 ] string1 and string2 are equal
[ string1 != string2 ] string1 and string2 are not equal
[ string1 \< string2 ] string1 is lexically less than string2(e.g. 'a' is less than 'b')
[ string1 \> string2 ] string1 is lexically greater than string2(e.g. 'b' is greater than 'a')
[ -z string ] string is zero (e.g. a empty string)
[ -n string ] string is nonzero (e.g. a VAR string)
[ -e file ] file exists
[ -f file ] file is a file
[ -d file ] file is a directory
[ -c file ] file is a character device
[ -b file ] file is a block device
[ -p file ] file is a named pipe
[ -s file ] file is not empty
[ -k file ] file's sticky bit is set
[ -S file ] file is a socket
[ -L file ] file is a symbolic link
[ -r file ] file is readable by user
[ -w file ] file is writeable by user
[ -x file ] file is executeable by user
[ -O file ] file is owner by user
[ -G file ] file is group owned by a greoup
[ -u file ] file has its set user ID bit set
[ -g file ] file has its group user ID bit set
[ file1 -nt file2 ] file1 is newer than file2
[ file1 -ot file2 ] file1 is older than file2
[ file -ef file2 ] file1 is another name for file2
[ n1 -eq n2 ] true if integer n1 = integer n2
[ n1 -ne n2 ] true if integer n1 <> n2
[ n1 -gt n2 ] true if n1 > n2
[ n1 -ge n2 ] true if n1 >= n2
[ n1 -lt n2 ] true if n1 < n2
[ n1 -le n2 ] true if n1 <= n2

一個常見的問題是, 在做字串比較的時候, 會有遇到空字串比較的問題, 進而造成以下的 error :

[: =: unary operator expected

舉例, 你的比較式是這樣寫的:

#!/bin/bash

cat $1 |
while read line; do
name=`echo $line | cut -d: -f1`
passwd=`echo $line | cut -d: -f2`

if [ $name = "hsu" ]; then
echo "$name found !!!!"
exit 5
fi
done

而且你有一個檔案內容如下:

lee:11111
:33333
hsu:333344

那麼你就會遇到這樣的 error :

./1.sh: line 8: [: =: unary operator expected
hsu found !!!!

雖然有找到, 但是卻發生一個錯誤, 此時修正方式可以在 $name 變數加上雙引號, 變成:

if [ "$name" = "hsu" ]; then

這樣就可以解決這個問題了. (想知道原因的話, 可以利用 sh -x 方式執行一次就知道了)
case 敘述
case 敘述與 if-then-else 效用類似, 請參考下述例子 :

$ cat myscript9
#!/bin/sh
case $1 in
[a-z]*) echo "starts with lower case"
;;
[A-Z]*) echo "starts with upper case"
;;
?*) echo "starts with something else"
;;
*) echo "doesn't start"
esac

case敘述是由 case 開頭與 esac (case的到寫) 組合而成, 而每一個判斷之後的兩個分號 (;;) 就是代表 break 的功能, 也就是說遇到 ;;
就會跳出整個 case 判斷式.

而上述的範例能夠判斷script所附帶的參數, 若參數為小寫字母開頭,則印出 "starts with lower case", 反之若是大寫字母開頭, 則印出
"starts with uppper case".

再用一個簡單的例子說明 :

$ cat myscript10
#!/bin/sh
case $1 in
0) echo zero ;;
1) echo one ;;
2) echo two ;;
3) echo three ;;
4) echo four ;;
5) echo five ;;
6) echo six ;;
7) echo seven ;;
8) echo eight ;;
9) echo night ;;
*) echo $1 ;;
esac

迴圈 for while loop
迴圈的宣告基本上所有的語言都是類似, 也就是都靠while, until 或者 for 這兩個方法來做迴圈.
while迴圈
$ cat myloop1
#!/bin/sh
read -r filename
while [ ! -f $filename ]; do
echo "--> $filename does not exist"
read -r filename
done
echo "$filename name OK"

$ myloop1
/etc/password
--> /etc/password does not exist
/etc/groups
--> /etc/groups does not exist
/etc/group
/etc/group name OK
$

說明 :
執行後, 會等待使用者輸入一個檔名, 接著會檢查該輸入字串是否真為一個檔案 (利用 -f 判斷), 若是
則跳出 while loop 並且印出 "檔名 name OK" 反之, 則印出 "--> 檔名 does not exist" , 並繼續
要求使用者輸入.

還有一種就是所謂的無窮迴圈, 通常是特殊用途才會這樣做啦, 或者加上判斷式, 同時利用 break
來跳出迴圈. 例如, 我要無窮盡地每隔十秒顯示時間 :

while [ 1 ]; do
date
sleep 10
done

實際應用 break 則可以參考以下範例

while [ 1 ]; do
HOUR=`date +'%H'`
if [ $HOUR -eq 10 ]; then
echo "OH OH, it's already 10:00, i got to go"
break
fi
sleep 5
done

上面的範例說明, 持續每五秒檢查一次, 是否已經是 10 點鐘了, 若已經 10 點, 則 break 跳出 while 迴圈.
until 迴圈
同 while , until 的功用與語法很類似, 請參考

$ cat myloop2
#!/bin/sh
until who | grep dino > /dev/null; do
sleep 10
done
echo "dino has logged in"

$ myloop2 &
[2] 9281
$
$
$ dino has logged in

我們再用一個例子來讓迴圈多點變化 :

$ cat myloop3
#!/bin/sh
i=1
while [ $i != 7 ]; do
echo $i
i=`expr $i + 1`
done

$ myloop3
1
2
3
4
5
6
$

這個範例 我想就不用怎麼說明了, 不過利用這個範例跟大家分享一下, 我常常用來做倒數計時的一個迴圈 :

#!/bin/sh
interval=10
total=1
while [ $total -le 5 ]; do
i=1
while [ $i -le $interval ]; do
echo -e "$total / $i / $interval \r\c"
sleep 1
i=`expr $i + 1`
done
total=`expr $total + 1`
done

請大家試試 就可以知道 這大概是什麼用的, 不過有時候echo 的語法 似乎在各種不同的 shell (e.g. /bin/sh, /bin/bash)
之間 並不完全相同 這可能要花一點點時間去確認的.
for 迴圈
繼續談到 for 迴圈, for 迴圈通常使用在比較有明確範圍的情況, 例如 :

$ cat myloop4
#!/bin/sh
for foo in *; do
if [ -f $foo ]; then
echo "$foo is a file"
elif [ -d $foo ]; then
echo "$foo is a directory"
else
echo "$foo is not a file, nor directory"
fi
done

$ myloop4
snake.txt is a file
tab.txt is a file
tinrc.txt is a file
tmp is a directory
tmp1 is a file

for 的迴圈也可以另外外一種類似 C 語言的那種運作方式, 例如以下這個範例:

for ((index=0; index<10; index++)); do
echo "Hello, this is : $index"
done




shell script的陣列 (array) 處理
陣列(array)的用途應該不用特別說明, 就是讓你用變數更方便, 用來處理相類型的資料更方便.
所以, 用實例說明比較快:


比如說, 我今天要寄信給三個管理者, 沒有陣列的時候, 可以這樣寫:

#!/bin/bash
admin1=[email protected]
admin2=[email protected]
admin3=[email protected]

mail -s "Log file" $admin1 < $mylog # $mylog 隨便定義
mail -s "Log file" $admin2 < $mylog # $mylog 隨便定義
mail -s "Log file" $admin3 < $mylog # $mylog 隨便定義

這是腳踏實地的寫法, 但是比較彈性的作法:

#!/bin/bash
admins=([email protected] [email protected] [email protected])

for name in ${admins[@]}; do
mail -s "Log file" $name < $mylog
done

或者這樣的 array 存取也是一樣的:

#!/bin/bash
admins=([email protected] [email protected] [email protected])

for ((i=0; i<${#admins[@]}; i++)); do #請注意 (( )) 雙層括號
mail -s "Log file" ${admins[$i]} < $mylog # thanks to keng.tisy@msa
done

所以重點:
${#array[@]} 代表所有array總數
${array[0]} 是array的第一個變數值, 也就是從0開始, 最大值-1也就是最後一個值

另外以下也提供一個常用來指派array的方法, 例如我要將檔案內的每一行定義到一個array變數內, 我可能會這樣做:

filename=/tmp/my_file
index=0
while read line; do
VARS[$index]="$line"
index=`expr $index + 1`
done < $filename

接著就可以利用另外一個 for loop 進行顯示了 :

for ((index=0; index<${#VARS[@]}; index++)); do
echo "[$index]: ${VARS[$index]}"
done

這邊再舉一個例子, 比如說我們有一個設定檔案, 裡面定義了多台主機, 我要將這些主機定義至 array 內.

舉例: config.ini 定義了以下設定:

SERVER=192.168.1.1,192.168.1.2,192.168.1.3

利用以下 shell script 可以把這串設定, 轉換成一個 SERVERS[] 的陣列喔 :

SERVERS=(`grep ^SERVER config.ini | cut -d= -f2 | sed 's/,/ /g'`)

接著就可以利用 for 迴圈顯示這個陣列了 :

for ((index=0; index<${#SERVERS[@]}; index++)); do
echo "SERVERS[$index] => ${SERVERS[$index]}"
done

利用陣列 (array) 來處理字串
Array也可以直接用來針對字串進行處理, 舉例說明, 今天系統時間是一大串日期與時間, 但是我們今天只需要將字串中的日期取出來, 這個時候, 我們就可以這樣進行 :

strings="201109201300"
echo "${strings:0:1}" #從第0個位置, 取出一個字元, 所以這一個結果會顯示 2
echo "${strings:0:2}" #會顯示 20
echo "${strings:0:8}" #就會顯示我們所需要的 20110920 了




sed 字串編輯器
將 filename 檔案內的 Giga 字串取代成 GigaRama
$ sed s/Giga/GigaRama/ filename

但是我們這樣只能做 stdout , 若是要把 file1 裡面的 Giga 都取代成 GigaRama 的話, 我們可以這樣做 :
$ cat file1 | sed s/Giga/GigaRama/ > file2

將 filename 檔案內的 xfish 字串那一行刪除
$ sed /xfish/d filename

同樣, 若是要將修改過的檔案變成一個新檔案, 可以這樣做 :
$ cat file1 | sed /xfish/d > file2

指定哪一行,將之刪除 (這裡是指定第四行 刪除)
$ sed '4d' filename

將filename的第一行到第幾行,將之刪除 (這裡是指定第一行到第四行 刪除)
$ sed '1,4d' filename

將filename的第一行到第五行印出
$ sed -n 1,5p filename

將 file 檔案內的出現 xfish 字串的那一行單獨寫到 file2 內
$ sed -n '/xfish/w file2' file

萬用字元的使用,將 file 檔案內的 xfis? 哪一行寫到 file2 內
$ sed '/xfis./w file2' file

萬用字串的使用,將 file 檔案內的 xfis* 哪一行寫到 file2 內
$ sed '/xfis*/w file2' file

選定字元的使用,將 file 檔案內的 xfis[abcd] 哪一行寫到 file2 內
$ sed '/xfis[abcd]/w file2' file

特別符號的取消,利用 /
$ sed s/\/\/ file

一行的起頭的取代,將 file 檔案的每一行起頭都加上 Hi..
$ sed s/^/Hi.. / file

一行的結尾的取代,將 file 檔案的每一行結尾都加上 Hi..
$ sed s/$/Hi.. / file

多重條件的指定,利用 -e 選項
$ sed -e 's/Giga/GigaRama/' -e 's/^/Hi../' file
回覆文章

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 1 位訪客