shell study

shell記錄

執行腳本

  • 做爲可執行程序
chmod +x ./test.sh  #使腳本具備執行權限
./test.sh  #執行腳本
  • 做爲解釋器執行
/bin/sh test.sh
/bin/php test.php

變量使用

name='bob'
echo $name
echo "my name id $name"
echo "Hello,"$name"!"
echo ${#name}               #輸出 4 (長度)

string="你原本就很帥"
echo "長度"${#string}
echo ${string:1:4}          #從第二個字符開始截取4個字符

echo `expr index "$string" 原本`  #查找字符本或來的位置(哪一個字母先出現就計算哪一個)


##shell數組
array_name=(value0 value1 value2 value3)
echo ${array_name[@]}                       #@獲取數組全部元素
length=${#array_name[@]}                    #獲取數組長度
echo $length
lengthn=${#array_name[2]}                   #獲取第二個元素的長度
echo $lengthn

註釋

#----------------------------------
# 這是一個註釋
# author:walkingsun
#----------------------------------

# 多行註釋
:<<EOF
註釋內容...
註釋內容...
註釋內容...
EOF


:<<!
註釋內容...
註釋內容...
註釋內容...
!

shell傳遞參數

#!/bin/bash

echo "Shell 傳遞參數實例!";
echo "執行的文件名:$0";                       # $0 爲執行的文件名
echo "第一個參數爲:$1";
echo "第二個參數爲:$2";
echo "第三個參數爲:$3";

執行git

./test.sh 1 2 3
參數處理    說明
$#  傳遞到腳本的參數個數
$*  以一個單字符串顯示全部向腳本傳遞的參數。
如"$*"用「"」括起來的狀況、以"$1 $2 … $n"的形式輸出全部參數。
$$  腳本運行的當前進程ID號
$!  後臺運行的最後一個進程的ID號
$@  與$*相同,可是使用時加引號,並在引號中返回每一個參數。
如"$@"用「"」括起來的狀況、以"$1" "$2" … "$n" 的形式輸出全部參數。
$-  顯示Shell使用的當前選項,與set命令功能相同。
$?  顯示最後命令的退出狀態。0表示沒有錯誤,其餘任何值代表有錯誤。

$* 與 $@ 區別:

相同點:都是引用全部參數。
不一樣點:只有在雙引號中體現出來。假設在腳本運行時寫了三個參數 一、二、3,,則 " * " 等價於 "1 2 3"(傳遞了一個參數),而 "@" 等價於 "1" "2" "3"(傳遞了三個參數)。

運算符

## 算數運算符
運算符 說明  舉例
+   加法  `expr $a + $b` 結果爲 30。
-   減法  `expr $a - $b` 結果爲 -10。
*   乘法  `expr $a \* $b` 結果爲  200。
/   除法  `expr $b / $a` 結果爲 2。
%   取餘  `expr $b % $a` 結果爲 0。
=   賦值  a=$b 將把變量 b 的值賦給 a。
==  相等。用於比較兩個數字,相同則返回 true。 [ $a == $b ] 返回 false。
!=  不相等。用於比較兩個數字,不相同則返回 true。   [ $a != $b ] 返回 true。

## 關係運算符
-eq 檢測兩個數是否相等,相等返回 true。    [ $a -eq $b ] 返回 false。
-ne 檢測兩個數是否不相等,不相等返回 true。  [ $a -ne $b ] 返回 true。
-gt 檢測左邊的數是否大於右邊的,若是是,則返回 true。 [ $a -gt $b ] 返回 false。
-lt 檢測左邊的數是否小於右邊的,若是是,則返回 true。 [ $a -lt $b ] 返回 true。
-ge 檢測左邊的數是否大於等於右邊的,若是是,則返回 true。   [ $a -ge $b ] 返回 false。
-le 檢測左邊的數是否小於等於右邊的,若是是,則返回 true。   [ $a -le $b ] 返回 true。


## 布爾運算符
運算符 說明  舉例
!   非運算,表達式爲 true 則返回 false,不然返回 true。  [ ! false ] 返回 true。
-o  或運算,有一個表達式爲 true 則返回 true。  [ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a  與運算,兩個表達式都爲 true 才返回 true。  [ $a -lt 20 -a $b -gt 100 ] 返回 false。

## 邏輯運算符
&&  邏輯的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
||  邏輯的 OR  [[ $a -lt 100 || $b -gt 100 ]] 返回 true

## 字符串運算符
=   檢測兩個字符串是否相等,相等返回 true。  [ $a = $b ] 返回 false。
!=  檢測兩個字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z  檢測字符串長度是否爲0,爲0返回 true。  [ -z $a ] 返回 false。
-n  檢測字符串長度是否爲0,不爲0返回 true。 [ -n "$a" ] 返回 true。
str 檢測字符串是否爲空,不爲空返回 true。   [ $a ] 返回 true。


## 文件測試運算符

操做符 說明  舉例
-b file 檢測文件是不是塊設備文件,若是是,則返回 true。  [ -b $file ] 返回 false。
-c file 檢測文件是不是字符設備文件,若是是,則返回 true。 [ -c $file ] 返回 false。
-d file 檢測文件是不是目錄,若是是,則返回 true。 [ -d $file ] 返回 false。
-f file 檢測文件是不是普通文件(既不是目錄,也不是設備文件),若是是,則返回 true。    [ -f $file ] 返回 true。
-g file 檢測文件是否設置了 SGID 位,若是是,則返回 true。  [ -g $file ] 返回 false。
-k file 檢測文件是否設置了粘着位(Sticky Bit),若是是,則返回 true。  [ -k $file ] 返回 false。
-p file 檢測文件是不是有名管道,若是是,則返回 true。   [ -p $file ] 返回 false。
-u file 檢測文件是否設置了 SUID 位,若是是,則返回 true。  [ -u $file ] 返回 false。
-r file 檢測文件是否可讀,若是是,則返回 true。  [ -r $file ] 返回 true。
-w file 檢測文件是否可寫,若是是,則返回 true。  [ -w $file ] 返回 true。
-x file 檢測文件是否可執行,若是是,則返回 true。 [ -x $file ] 返回 true。
-s file 檢測文件是否爲空(文件大小是否大於0),不爲空返回 true。 [ -s $file ] 返回 true。
-e file 檢測文件(包括目錄)是否存在,若是是,則返回 true。    [ -e $file ] 返回 true。

echo

echo -e "OK! \n" # -e 開啓轉義 \n顯示換行

echo -e "OK! \c" # -e 開啓轉義 \c 不換行

echo "It is a test" > myfile                        #顯示結果定向到文件

echo `date`                                         #顯示命令執行結果

printf

printf  format-string  [arguments...]

模仿c程序庫的printf(php也是如此)github

printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg
printf "%-10s %-8s %-4s\n" walkingsun boy 150
# %s %c %d %f都是格式替代符
# %-10s 指一個寬度爲10個字符(-表示左對齊,沒有則表示右對齊),任何字符都會被顯示在10個字符寬的字符內,若是不足則自動以空格填充,超過也會將內容所有顯示出來。
# %-4.2f 指格式化爲小數,其中.2指保留2位小數。

test

Shell中的 test 命令用於檢查某個條件是否成立,它能夠進行數值、字符和文件三個方面的測試。shell

# 數值測試
參數  說明
-eq 等於則爲真
-ne 不等於則爲真
-gt 大於則爲真
-ge 大於等於則爲真
-lt 小於則爲真
-le 小於等於則爲真


# 字符串測試
=   等於則爲真
!=  不相等則爲真
-z 字符串  字符串的長度爲零則爲真
-n 字符串  字符串的長度不爲零則爲真

# 文件測試
-e 文件名  若是文件存在則爲真
-r 文件名  若是文件存在且可讀則爲真
-w 文件名  若是文件存在且可寫則爲真
-x 文件名  若是文件存在且可執行則爲真
-s 文件名  若是文件存在且至少有一個字符則爲真
-d 文件名  若是文件存在且爲目錄則爲真
-f 文件名  若是文件存在且爲普通文件則爲真
-c 文件名  若是文件存在且爲字符型特殊文件則爲真
-b 文件名  若是文件存在且爲塊特殊文件則爲真

流程控制

if ... else ...

if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi    # 查詢進程中命令行包含ssh的數量是否大於1,是返回true   -c 統計數量

if ... elseif ...else ... fi數組

if condition1
then
    command1
elif condition2
then
    command2
else
    commandN
fi

for

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

實例:bash

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

## 順序輸出字符串中的字符
for str in 'This is a string'
do
    echo $str
done

while

while condition
do
    command
done

實例:markdown

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

無線循環app

while :
do
    command
done
或者

while true
do
    command
done
或者

for (( ; ; ))

until

until 循環
until 循環執行一系列命令直至條件爲 true 時中止。

until 循環與 while 循環在處理方式上恰好相反。

通常 while 循環優於 until 循環,但在某些時候—也只是極少數狀況下,until 循環更加有用。

until 語法格式:

until condition
do
    command
done

case

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

實例ssh

echo '輸入 1 到 4 之間的數字:'
echo '你輸入的數字爲:'
read aNum
case $aNum in
    1)  echo '你選擇了 1'
    ;;
    2)  echo '你選擇了 2'
    ;;
    3)  echo '你選擇了 3'
    ;;
    4)  echo '你選擇了 4'
    ;;
    *)  echo '你沒有輸入 1 到 4 之間的數字'
    ;;
esac

跳出循環

break和continue (同PHP)函數

esac
須要一個esac(就是case反過來)做爲結束標記,每一個case分支用右圓括號,用兩個分號表示break。

函數

[ function ] funname [()]

{

    action;

    [return int;]

}

實例:

funWithReturn(){
    echo "這個函數會對輸入的兩個數字進行相加運算..."
    echo "輸入第一個數字: "
    read aNum
    echo "輸入第二個數字: "
    read anotherNum
    echo "兩個數字分別爲 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "輸入的兩個數字之和爲 $? !"


# 傳參
funWithParam(){
    echo "第一個參數爲 $1 !"
    echo "第二個參數爲 $2 !"
    echo "第十個參數爲 $10 !"
    echo "第十個參數爲 ${10} !"
    echo "第十一個參數爲 ${11} !"
    echo "參數總數有 $# 個!"
    echo "做爲一個字符串輸出全部參數 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
#注意,$10 不能獲取第十個參數,獲取第十個參數須要${10}。當n>=10時,須要使用${n}來獲取參數。

注意

參數處理    說明
$#  傳遞到腳本的參數個數
$*  以一個單字符串顯示全部向腳本傳遞的參數
$$  腳本運行的當前進程ID號
$!  後臺運行的最後一個進程的ID號
$@  與$*相同,可是使用時加引號,並在引號中返回每一個參數。
$-  顯示Shell使用的當前選項,與set命令功能相同。
$?  顯示最後命令的退出狀態。0表示沒有錯誤,其餘任何值代表有錯誤。

輸入輸出重定向

命令  說明
command > file  將輸出重定向到 file。
command < file  將輸入重定向到 file。
command >> file 將輸出以追加的方式重定向到 file。
n > file    將文件描述符爲 n 的文件重定向到 file。
n >> file   將文件描述符爲 n 的文件以追加的方式重定向到 file。
n >& m  將輸出文件 m 和 n 合併。
n <& m  將輸入文件 m 和 n 合併。
<< tag  將開始標記 tag 和結束標記 tag 之間的內容做爲輸入。

實例

who > users   #執行 who 命令,它將命令的完整的輸出重定向在用戶文件中(users)

重定向深刻

  • 標準輸入文件(stdin):stdin的文件描述符爲0,Unix程序默認從stdin讀取數據。
  • 標準輸出文件(stdout):stdout 的文件描述符爲1,Unix程序默認向stdout輸出數據。
  • 標準錯誤文件(stderr):stderr的文件描述符爲2,Unix程序會向stderr流中寫入錯誤信息
command 2 > file    #stderr 重定向到 file

command 2 >> file   #stderr 追加到 file 文件末尾

command > file 2>&1   #stdout 和 stderr 合併後重定向到 file

command < file1 >file2  #stdin 和 stdout 都重定向,command 命令將 stdin 重定向到 file1,將 stdout 重定向到 file2

Here Document

command << delimiter
    document
delimiter

實例

在命令行中經過 wc -l 命令計算 Here Document 的行數:

$ wc -l << EOF
    歡迎來到
    菜鳥教程
    www.runoob.com
EOF

3          # 輸出結果爲 3 行
$

/dev/null 文件

若是但願執行某個命令,但又不但願在屏幕上顯示輸出結果,那麼能夠將輸出重定向到 /dev/null:

$ command > /dev/null

/dev/null 是一個特殊的文件,寫入到它的內容都會被丟棄;若是嘗試從該文件讀取內容,那麼什麼也讀不到。可是 /dev/null 文件很是有用,將命令的輸出重定向到它,會起到"禁止輸出"的效果。

若是但願屏蔽 stdout 和 stderr,能夠這樣寫:

$ command > /dev/null 2>&1

shell文件包含

. filename   # 注意點號(.)和文件名中間有一空格

或

source filename

nohup 退出賬戶/關閉終端以後繼續運行相應的進程

nohup command > myout.file 2>&1 &

0 – stdin (standard input),1 – stdout (standard output),2 – stderr (standard error) ;
2>&1是將標準錯誤(2)重定向到標準輸出(&1),標準輸出(&1)再被重定向輸入到myout.file文件中。

& : 指在後臺運行

&是指在後臺運行,但當用戶推出(掛起)的時候,命令自動也跟着退出

sh test.sh &

使命令永久的在後臺執行

nohup COMMAND &

實踐

這裏會記錄典型的shell應用場景

場景一:系統日誌太多,佔空間,想清理掉一個月以前的日誌,只保留近期一個月的日誌

#!/bin/sh
# 清理日誌
# author:walkingsun
# test

path=/data/app/WindBlog/runtime/logs/                   #指定清理目錄
timeout=`expr 30 \* 86400`                              #過時時間(當前設爲30天)
systime=`date +%s`                                      #獲取當前系統的時間 (秒爲單位)

files=$(ls $path)
for filename in $files
do
  fileuptime=`stat -c %Y $path$filename`                #獲取文件修改時間(秒)
  if [ $[ $systime - $fileuptime ] -gt $timeout ]
  then
     echo $path$filename
     echo `rm -rf $apth$filename`
  fi
done

給定一個文件 file.txt,轉置它的內容。

你能夠假設每行列數相同,而且每一個字段由 ' ' 分隔.

示例:

假設 file.txt 文件內容以下:
    
    name age
    alice 21
    ryan 30
    應當輸出:
    
    name alice ryan
    age 21 30

解答

#!/bin/bash

awk '{for(i=1;i<=NF;i++){if(NR==1){data[i]=$i}else{data[i]=data[i]" "$i}}}END{for(i=1;i<=NF;i++) print data[i]}' file.txt

給定一個包含電話號碼列表(一行一個電話號碼)的文本文件 file.txt,寫一個 bash 腳本輸出全部有效的電話號碼。

你能夠假設一個有效的電話號碼必須知足如下兩種格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一個數字)

你也能夠假設每行先後沒有多餘的空格字符。

示例:

假設 file.txt 內容以下:

987-123-4567

123 456 7890

(123) 456-7890

你的腳本應當輸出下列有效的電話號碼:

987-123-4567

(123) 456-7890

#!/bin/bash

awk '/^(\([0-9]{3}\) |[0-9]{3}-)[0-9]{3}-[0-9]{4}$/{print $0}' file.txt

寫一個 bash 腳本以統計一個文本文件 words.txt 中每一個單詞出現的頻率。

爲了簡單起見,你能夠假設:
    
    words.txt只包括小寫字母和 ' ' 。
    每一個單詞只由小寫字母組成。
    單詞間由一個或多個空格字符分隔。
    示例:
    
    假設 words.txt 內容以下:
    
    the day is sunny the the
    the sunny is is
    你的腳本應當輸出(以詞頻降序排列):
    
    the 4
    is 3
    sunny 2
    day 1
#!/bin/bash

awk '{for(i=1;i<=NF;i++){a[$i]=a[$i]+1}}END{for(k in a){print k" "a[k]}}' words.txt |sort -nr -k 2
相關文章
相關標籤/搜索