歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> SHELL編程 >> Linux.Shell編程筆記-基本元素

Linux.Shell編程筆記-基本元素

日期:2017/3/1 13:37:00   编辑:SHELL編程

第三章 編程的基本元素

再識變量

實例對 各種情況的測試計算

[hcr@slave2 temp]$ vim variable.sh
#!/bin/bash
a=2334
let "a += 1"
echo "a = $a"
echo
 
#替換成字母
b=${a/23/BB}
 
echo "b = $b"
 
declare -i b
echo "b = $b"
let  "b += 1"
echo "b =$b"
echo
 
#替換成數字
c=BB34
echo "c = $c"
d=${c/BB/23}
echo "d = $d"
let "d += 1"
echo "d = $d"
echo
# 為空值
 
e=""
 
echo "e = $e"
let e+=1
echo "e = $e"
 
# 為null
echo
 
echo "f = $f"
let "f += 1"
 
echo "f = $f"
echo 

shell中有3種變量:用戶變量、位置變量{pracessing parameter)和環境變量。其中用戶變

量在編程過程中使用最多,位置變量在對參數判斷和命令返回值判斷時會使用,環境變量主要是在程序運行的時候需要設置。

用戶變量

聲明變量

VarName=varValue

聲明本地變量 local

但是必須得在腳本中去寫。

Shell中的特殊符號

特殊字符

含義

用法

~

主目錄,相當於 $HOME

cd ~

#

shell腳木中的注釋

# 注釋

··

命令替換.例如·pwd·返回pwd命令執行的結果字符串

abc=·which hadoop·

$

變量表達式符號

"a = $a"

&

後台作業,將此符號置於命令末端,則讓命令於後台運行

sh start.sh &

*

字符串通配符

ls a* >>f.txt

()

在括號中執行子shell命令

(let "e = $b + $c";echo $e)

\

轉義下一個字符

\\

|

管道

ps -ef |grep tomcat

[]

開始字符集通配符號和 if表達式

ls [a-z]*.sh
if [ "$1" != 0 ];then if

{}

命令塊

a=${aa/12/34}

;

shell命令分隔符

(let "e = $b + $c";echo $e)

‘’

強引用

a='abc';

“”

弱引用

a="$a"

<

輸入重定向

cat < a.txt > b.txt

>

輸出重定向

cat a.txt > b.txt

/

路徑名目錄分隔符

cd /

單個任意字符

ll ??.sh

邏輯NOT

ll [!a-b].txt

替換運算符

 

:-
${varname:-word}

在符號前的變量如果存在且非空則返回符號前的變量,否則返回符號後的字符

echo ${name:-'else'}

:=
${varname:=word}

在符號前的變量如果存在且非空則返回符號前的變量,否則講把符號後的字符賦值給符號前的變量

echo ${name:='else'}

:?
${varname:?word}

在符號前的變量如果存在且非空則返回符號前的變量,否則打印符號後的字符

echo ${name:?'else'}

:+
${varname:+word}

在符號前的變量如果存在則返回符號後的變量,否則返回null

echo ${name:+'else'}

如果上邊的替換運算符去掉冒號(:) ,就是一樣用但是條件少了一個且非空

匹配運算符

 

${varname#pattern}

必須以開頭匹配pattern模式的最短字符串將被刪除,返回剩余的字符串。否則返回全部

echo ${path#/*sr/}

${varname##pattern}

必須以開頭匹配pattern模式的最長字符串將被刪除,返回剩余的字符串。否則返回全部

echo ${path##/*sr/}

${varname%pattern}

必須以結尾匹配pattern模式的最短字符串將被刪除,返回剩余的字符串。否則返回全部

echo ${path%/*}

${varname%%pattern}

必須以結尾匹配pattern模式的最長字符串將被刪除,返回剩余的字符串。否則返回全部

echo ${path%%/*}

${varname/pattern/string}

匹配開始pattern模式的第一個字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。

echo ${path/hadoop/hadoop-0.2}

${varname//pattern/string}

匹配開始pattern模式的所有字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。

echo ${path//hadoop/hadoop-0.2}

${varname/#pattern/string}

必須以開頭匹配開始pattern模式的最短字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。

echo ${path/#\/usr/\/www}或者
echo ${path/#‘/usr’/‘/www’}

${varname/%pattern/string}

必須以結尾匹配開始pattern模式的最短字符串將被替換成string,如果string為null那麼匹配的東西將被刪除,返回處理後的數據。

echo ${path/%\/usr/\/www}

位置變量

位置變量也稱系統變量、位置參數,是shell腳本運行時傳遞給腳本的參數,同時也表示在shell函數內部的函數參數。它們的名稱是以數字命名(由於歷史原因,直接引用的位置參數只能從$0到$9超過這個范圍則必須用括號括起來,如${10}。

shell內置了一個shift命令,shift命令可以“截去”參數列表最左端的一個。執行了shift後,$1的值將永遠一丟失,而$2的舊值會被賦給$1,以此類推。表達參數總數的$#將會減一。shift是個可帶參數的命令,例如,shift 2表示截去兩個參數,而單純的shift命令的含義是shift 1。

[root@ebsdi-23260-oozie tmpFile]# cat shift.sh
#!/bin/bash
 
while [ -e $1 ];
do
        cat $1
        shift
done
[root@ebsdi-23260-oozie tmpFile]# vim for.sh
#!/bin/bash
 
for file in $*
do
 cat $file
done
~
環境變量

常用的環境變量

名稱

描述

PATH

命令搜索路補,以胃號為分隔符。注意與D0S不同的是,
當前目錄不在系統路徑裡

HOME

用戶home目錄的路徑名,是cd命令的默認參數

COLUMNS

定義了命令編輯模式下可使用命令行的長度

EDITOR

默認的行編輯器

VISUAL

默認的可視編輯器

FCEDIT

命令fc使用的編輯器

HISTFILE

命令歷史文件

HISTSIZE

命令歷史文件中最多可包含的命令條數

HISTFILESIZE

命令歷史文件中包含的最大行數

IFS

定義shell使用的分隔符

MAIL

指向一個需要shell監視其修改時問的文件。
當該文件修改後,Shell將發消息"You have a mail"給用戶

MAILCHECK

shell檢查MAIL文件的周期,單位是秒。

SHELL

shell的路徑名

TERM

終端類型

TMOUT

shell自動退出的時間,單位為秒,若設為0,則禁正shell自動退出

PROMPT_COMMAND

指定在卞命令提示符前應執行的命令

PS1

主命令提示符

PS2

二級命令提示符,命令執行過程中要求輸入數據時用

PS3

select的命令提示符

PS4

調試命令提示符

MANPATH

尋找手冊頁的路徑,以胃號分隔

LOGNAME

用戶登錄名

MAILPATH

功能與MAIL類似。但可以用一組文件,
以冒號分隔,每個文件後跟一個問號和一條發向用戶的消息

LD_LIBARAY_PATH

尋找庫的路徑,以冒號分割

啟動文件

shell使用一些啟動文件來協助創建一個運行環境,其中每個文件都有特定的用途,對登錄

和交互環境的影響也各不相同。/etc目錄下的文件提供全局設置,如果用戶主目錄下存在同名文件,它將覆蓋全局設置。

使用/bin/login讀取/etc/passwd文件成功登陸後,啟動了一個交互登錄shell。用命令行可以啟動一個交互非登錄shell(例如[prompt] $/hin/bash )。非交互shel l通常出現在shell腳本運行的時候,之所以稱為非交互的,因為它正在運行一個腳本,而且命令與命令之間並不等待用戶的輸入。

無論運行什麼shell,文件/etc/enviranment都先運行。即使用rexedc和rshd開始的shell,也應該設置定義在/etc/enviranment文件中的環境變量。

/etc/enviranment設置諸如最小搜索路徑、時區、語言等用戶環境。這個文件不是一個

shellscript,並且只接受以下數據格式:

name=<value>

(環境變量名=變量值)

init開始的所有進程都要執行這個文件,它影響所有的登錄shell .

函數

作為一種完整的編程語言,Linuxshell必定不能缺少函數( function)支持:一段獨立的程序

代碼用於執行一個完整的單項工作。函數復用是優質代碼的一大特征,故在一些大型的程序裡,常常可以見到函數的身影。

當shell執行函數時,並不獨立創建子進程。常用的做法是,將函數寫入其他文件中,當需要的時候才將它們載入腳本。

執行命令的順序

交互shell在獲得用戶輸入時,並不是直接就在PATH路徑中查找,而是按照固定順序依次移

找命令位置。搜索順序為;

別名 即使用aliascommand="..",創建的命令。

關鍵字 如if, fvro

函數 自定義的一些函數

內置命令 如cd, pwd等命令。

外部命令 即腳木或可執行程序,這才在path路徑中查找

由此可見,在同名時,函數的優先級高於腳本。可以使用內置命令 command,buildin 和enable改變優先級順序,它允許你將函數、別名和腳本文件定義成相同的名字,井選抒執行其中之一。

如果想要知道執行的命令是哪種類型,可以使用type命令。當重命名時,type命令會告訴你真正被執行的命令的來源是別名、函數或外部命令。

[houchangren@ebsdi-23260-oozie shell]$ type user_login
user_login is a function
user_login ()
{
if who | grep $1 >> /dev/null; then
echo " user $1 is on";
else
echo " user $1 is off";
fi
}
[houchangren@ebsdi-23260-oozie shell]$ type ll
ll is aliased to `ls -l --color=tty'
[houchangren@ebsdi-23260-oozie shell]$ type ls
ls is aliased to `ls --color=tty'
[houchangren@ebsdi-23260-oozie shell]$ type cat
cat is hashed (/bin/cat)

函數的使用規則

函數使用時,遵循一些重要規則:

》函數必須先定義,後使用。

》函數在當前環境下運行,共享調用它的腳木中的變量,並且,函數允許你以給位置參數賦值的方式向函數傳遞參數。函數體內部可以使用local限定詞創建局部變量。

》如果在函數中使用exit命令,會退出腳本。如果想退回到原本調用函數的地方,則使用 return命令。

》函數的return語句返回函數執行最後一條命令的退出狀態。

》使用內置命令export -f 可以將函數等出到子shell中。

》如果函數保存在其他文件巾,可以使用source或dot(就是圓點./start.sh)命令將它們裝入當前腳木。

》函數可以遞歸調用,並且沒有調用限制。

》可以使用declare -f 找到登錄會話中定義的函數。函數會按照字母順序打印所有的函數定義。這個定義列表可能會很長,需要使用文本閱讀器more或less查看。如果僅僅想看函數名,則使用declare -F語句。

自動加載

如果想在每次啟動系統時自動加載函數,則只需要將函數寫入啟動文件中。例如

$HOME/.profile中即可,則每次啟動時,source$HOME/.profile都會自動加載函數.

函數定義

函數定義

[houchangren@ebsdi-23260-oozie shell]$ cat user_login.sh
#!/bin/bash
 
function user_login(){
if who | grep $1 >> /dev/null ; then
echo " user $1 is on"
else
echo " user $1 is off"
fi
 
}
[houchangren@ebsdi-23260-oozie shell]$ source user_login.sh
[houchangren@ebsdi-23260-oozie shell]$ user_login2 23
bash: user_login2: command not found
[houchangren@ebsdi-23260-oozie shell]$ user_login erpmerge
 user erpmerge is on
[houchangren@ebsdi-23260-oozie shell]$ user_login hbase
 user hbase is off
[houchangren@ebsdi-23260-oozie shell]$ unset -f user_login

使用source 讀入文件內容

然後使用操作

unset -f 命令可以取消函數

函數的參數和返回值

由於函數是在當前shell中執行,所以變量對於函數和shell都可見。在函數內部對變量做的任何改動也會影響shell的環境。

參數 你可以像使用命令一樣,向函數傳遞位置參數,位置參數是函數私有的,對位置參數的任何操作並不會影響函數外部使用的枉何參數。

局部變量限定詞local 當使用local時,定義的變量為函數的內部變量。內部變量在函數退出時消失,不會影響到外部同名的變量。

返回方式return return命令可以在函數體內返回函數被調用的位置。如果沒有指定return的參數,則函數返回最後一條命令的退出狀態。return命令同樣也可以返回傳給它的參數。按照規定,return命令只能返回D到255之間的整數。如果在函數體內使用exit命令,則退出整個腳本。

[houchangren@ebsdi-23260-oozie shell]$ cat add.sh
#!/bin/bash
 
_add(){
let "sum=$1+$2"
return $sum
}
[houchangren@ebsdi-23260-oozie shell]$
[houchangren@ebsdi-23260-oozie shell]$ _add 12 23
[houchangren@ebsdi-23260-oozie shell]$ echo $?
35
條件控制和流程控制
條件控制

If/else

if who | grep 'sdfsdfds';
then echo 'right';
elseif who | grep 'sdfsdfsdfsd';
echo 'right';
else 
echo 'wrong';
fi
If [test] ;
 then
do cmd
elseif [test];
then
         docmd;
else
do cmd;
fi

ifelse組合,

if else

if elseif

if elseif if

退出狀態

每條命令或函數,在退出時都會返回一個小的整數值給調用它的程序。這就是命令或函數的退出狀態(exit status )。與c語言稍有不同的是,在判斷語句中,條件(cnndition)實際上是語句列表,而不是般的布爾表達式。

按照慣例,函數以及命令的退出狀態用0來表示成功,而非零表示失敗。

POSIX中定義了退出狀態對應的值

描述

0

成功

>0

在重定向或者單詞展開期間(~、變量、命令、算數展開、單詞切割等)操作失敗

1-125

命令退出失敗。特定退出值的定義,參見不同命令的定義

126

命令找到而無法執行命令文件

127

命令無法找到

>128

命令因受到信號而死亡

退出狀態和邏輯操作

Not and or

If [ !condition];
then
         statement
if
 
If [ condition && condition2];
then
         statement
if

 
If [ condition || condition2];
then
         statement
if
條件測試

If語句

if test 2 -gt 3; then  echo '大於'; fi
if [ 2 -gt 3 ]; then  echo '大於'; fi

注意點,在使用 [ ]這個的時候一定要記得參數和符號之前有空格

字符串比較

-z string

字符串string 為空串(長度為0)時返回真

-n string

字符串string 為非空串時返回真

str1 = str2

字符串str1 和字符串str2 相等時返回真

str1 == str2

同 =

str1 != str2

字符串str1 和字符串str2 不相等時返回真

str1 < str2

按字典順序排序,字符串str1 在字符串str2 之前

[houchangren@ebsdi-23260-oozie shell]$ cat if.sh
#!/bin/bash
if [ $1 = "test" ]
then
echo "right"
fi
[houchangren@ebsdi-23260-oozie shell]$ sh if.sh test
right
[houchangren@ebsdi-23260-oozie shell]$ sh if.sh test3
[houchangren@ebsdi-23260-oozie shell]$

字符串的操作符兩邊都必須有空格哦。

[houchangren@ebsdi-23260-oozie shell]$ cat checkUserIsExist.sh
#!/bin/sh
 
line=|grep $1 /etc/passwd |
if [ -n $line ]
then
        echo "user $1 exist"
fi
[houchangren@ebsdi-23260-oozie shell]$ sh checkUserIsExist.sh houchangren
user houchangren exist

整數數值比較

int1 -eq int2

如果int1 等於int2,則返回真

int1 -ne int2

如果int1 不等於int2,則返回真

int1 -lt int2

如果int1 小於int2,則返回真

int1 -le int2

如果int1 小於等於int2,則返回真

int1 -gt int2

如果int1 大於int2,則返回真

int1 -ge int2

如果int1 大於等於int2,則返回真

<

小於(在雙括號裡使用)

(("$a" < "$b"))

<=

小於等於 (在雙括號裡使用)

(("$a" <= "$b"))

>

大於 (在雙括號裡使用)

(("$a" > "$b"))

>=

大於等於(在雙括號裡使用)

(("$a" >= "$b"))

考 :http://blog.csdn.net/ruishenh/article/details/17998921

文件屬性檢查

-b filename

當filename 存在並且是塊文件時返回真(返回0)

-c filename

當filename 存在並且是字符文件時返回真

-d pathname

當pathname 存在並且是一個目錄時返回真

-e pathname

當由pathname 指定的文件或目錄存在時返回真

-f filename

當filename 存在並且是正規文件時返回真

-g pathname

當由pathname 指定的文件或目錄存在並且設置了SGID 位時返回真

-h filename

當filename 存在並且是符號鏈接文件時返回真 (或 -L filename)

-k pathname

當由pathname 指定的文件或目錄存在並且設置了"粘滯"位時返回真

-p filename

當filename 存在並且是命名管道時返回真

-r pathname

當由pathname 指定的文件或目錄存在並且可讀時返回真

-s filename

當filename 存在並且文件大小大於0 時返回真

-S filename

當filename 存在並且是socket 時返回真

-t fd

當fd 是與終端設備相關聯的文件描述符時返回真

-u pathname

當由pathname 指定的文件或目錄存在並且設置了SUID 位時返回真

-w pathname

當由pathname 指定的文件或目錄存在並且可寫時返回真

-x pathname

當由pathname 指定的文件或目錄存在並且可執行時返回真

-O pathname

當由pathname 存在並且被當前進程的有效用戶id 的用戶擁有時返回真(字母O 大寫)

-G pathname

當由pathname 存在並且屬於當前進程的有效用戶id 的用戶的用戶組時返回真

file1 -nt file2

file1 比file2 新時返回真

file1 -ot file2

file1 比file2 舊時返回真

f1 -ef f2

f1和f2硬鏈接到的是一個文件是為真

測試腳本

[houchangren@ebsdi-23260-oozie shell]$ ll
總計 24
-rw-rw-r-- 1 houchangren houchangren  51 01-08 10:46 add.sh
-rw-rw-r-- 1 houchangren houchangren  85 01-08 13:38 checkUserIsExist.sh
-rwxrwxr-x 1 houchangren houchangren 284 01-08 13:55 testalg.sh
[houchangren@ebsdi-23260-oozie shell]$ cat testalg.sh
#!/bin/bash
 
file=$1
if [ -d $file ]
then
echo "$file is dir"
elif [  -f $file ]
then
echo "$file is file "
        if [ -r $file ] && [ -w $file ] && [ -x $file ]
                then
                echo "You have read,write,execute permission  on $file";
        fi
else
echo "$file is neither a file and a directory"
fi
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh /etc
/etc is dir
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh ../
../ is dir
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh testalg.sh
testalg.sh is file
You have read,write,execute permission  on testalg.sh
[houchangren@ebsdi-23260-oozie shell]$ sh testalg.sh /dev/null
/dev/null is neither a file and a directory
[houchangren@ebsdi-23260-oozie shell]$ 

Case語句

當存在很多個邏輯判斷的時候if用起來就顯著那麼臃腫了。Case可以很簡潔的指定

case也是一個流程控制結構。Parscal中的case語句和C語言中的switch語句被用來測試諸

如整數和字符的簡單值。shell中的case語句。可以依據可包含通配符的模式測試字符串。

[houchangren@ebsdi-23260-oozie shell]$ cat testcase.sh
#!/bin/bash
case $1 in
    -f) echo "參數1是-f";;
    -d) echo "參數1是-d";;
    -x) echo "參數1是-x";;
    -w) echo "參數1是-w";;
    *)  echo "輸入的參數不是預先估的參數!";;
esac
[houchangren@ebsdi-23260-oozie shell]$ sh testcase.sh -w
參數1是-w
[houchangren@ebsdi-23260-oozie shell]$ sh testcase.sh -ll
輸入的參數不是預先估的參數!
循環控制

在眾多高級語言中,循環總是不可缺少的元素。循環一讓我們控制某些代碼的重復行為,或允許對多個對象操作。

for循環是最簡單的循環,我們在許多編程語言中都可以見到它的身影。在shell腳本裡,對象可以是命令行參數、文件名,或者任何、可以以列表格式建立的東西。

[houchangren@ebsdi-23260-oozie shell]$ for file in *.sh
> do
> echo $file
> done
add.sh
a.sh
checkUserIsExist.sh
if.sh
testalg.sh
testcase.sh
user_login.sh
[houchangren@ebsdi-23260-oozie shell]$

在for循環中,如果in list被省略,則默認為in"$@",即命令行參數的引用列表。就好像你已經輸入了for name in “$@”。

[houchangren@ebsdi-23260-oozie shell]$ cat testfor.sh
#!/bin/sh

for param
do
echo $param
done
[houchangren@ebsdi-23260-oozie shell]$ sh testfor.sh 1
1
[houchangren@ebsdi-23260-oozie shell]$ sh testfor.sh 1 2
1
2
[houchangren@ebsdi-23260-oozie shell]$ sh testfor.sh 1 2 3 4
1
2
3
4
[houchangren@ebsdi-23260-oozie shell]$

While /until

While 和傳統中的操作一樣

While [ condition ]

do

docmd

done

until [ condition ]

do

docmd

done

while和until的操作一樣,就是條件處理循環的時候是相反的。While是條件=true接著循環

跳出循環

break和continue語句允許對循環的運行精確控制:跳出循環或重新執行循環。

當嵌套層超過一層的時候可以指定break或者continue後加數字跳出(繼續)指定的層

[houchangren@ebsdi-23260-oozie shell]$ cat testwhile.sh
#!/bin/bash

num=0
while true
do
echo "while1- $num"
while true
do
echo "while2- $num"
while true
do
echo "while3- $num"
num=$(($num+1))
case $num in
5 ) break 2;;
10 ) break 3;;
* ) break 1 ;;
esac
done

done
if [ $num -ge $1 ];
then
break 1
fi
done
[houchangren@ebsdi-23260-oozie shell]$ sh testwhile.sh 10
while1- 0
while2- 0
while3- 0
while2- 1
while3- 1
while2- 2
while3- 2
while2- 3
while3- 3
while2- 4
while3- 4
while1- 5
while2- 5
while3- 5
while2- 6
while3- 6
while2- 7
while3- 7
while2- 8
while3- 8
while2- 9
while3- 9
[houchangren@ebsdi-23260-oozie shell]$

實例

[houchangren@ebsdi-23260-oozie shell]$ cat whileexample.sh
#!/bin/bash
author=false
list=false
file=""
 
while  [ $# -ge 0 ]
do
 case $1 in
        -f) file=$2;echo "filename:$file"; shift ;;
        -l) list=true;;
        -a) author=true;;
        --) shift;break ;;
        -*) echo $0:$1:unrecognized option ;;
        * ) break ;;
 esac
 shift
done
[houchangren@ebsdi-23260-oozie shell]$ sh whileexample.sh -f whileexample.sh
filename:whileexample.sh
[houchangren@ebsdi-23260-oozie shell]$ sh whileexample.sh -fx wer
whileexample.sh:-fx:unrecognized option
[houchangren@ebsdi-23260-oozie shell]$
用getopts工具來格式化參數

Getopts參考

http://www.2cto.com/os/201309/246174.html

[houchangren@ebsdi-23260-oozie shell]$ cat whileexample2.sh
#!/bin/bash
 
author=false
list=false
file=""
 
while getopts alf: opt
do
case $opt in
        f) file=$OPTARG;echo "file:$file" ;;
        l) list=true ;;
        a) author=ture;;
    esac
done
shift $(($OPTIND -1))
[houchangren@ebsdi-23260-oozie shell]$ sh  whileexample2.sh -f whileexample.sh
file:whileexample.sh
[houchangren@ebsdi-23260-oozie shell]$
Copyright © Linux教程網 All Rights Reserved