中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

linux腳本攻略

發布時間:2020-08-03 03:15:19 來源:網絡 閱讀:440 作者:九根蔥 欄目:系統運維

ls

#列出以a和o開頭的所有文件
[root@sh02-hap-bss-prod-consul03 ~]# ls
anaconda-ks.cfg  nss-pam-ldapd-0.9.8-1.gf.el7.x86_64.rpm  openldap-clients-2.4.44-21.el7_6.x86_64.rpm  original-ks.cfg  tools
[root@sh02-hap-bss-prod-consul03 ~]# ls [ao]*
anaconda-ks.cfg  openldap-clients-2.4.44-21.el7_6.x86_64.rpm  original-ks.cfg

#[0-9]表示任意單個數字
#[!0-9]表示非數字開頭的字符串
[root@sh02-hap-bss-prod-consul03 ~]# ls
1  3   anaconda-ks.cfg                          openldap-clients-2.4.44-21.el7_6.x86_64.rpm  tools
2  44  nss-pam-ldapd-0.9.8-1.gf.el7.x86_64.rpm  original-ks.cfg
[root@sh02-hap-bss-prod-consul03 ~]# ls [!0-9]*
anaconda-ks.cfg  nss-pam-ldapd-0.9.8-1.gf.el7.x86_64.rpm  openldap-clients-2.4.44-21.el7_6.x86_64.rpm  original-ks.cfg

tools:
libnss-cache  nsscache
[root@sh02-hap-bss-prod-consul03 ~]# ls [0-9]*
1  2  3  44

rm

#刪除以數字開頭的文件
rm -f [0-9]*

#刪除非以數字開頭的文件
[root@sh02-hap-bss-prod-consul03 test]# ls
1  2  3  4  a  aa  b  bb
[root@sh02-hap-bss-prod-consul03 test]# rm -f [!0-9]*
[root@sh02-hap-bss-prod-consul03 test]# ls
1  2  3  4

echo

  • 默認情況下,echo會將一個換行符追加到文本尾部,可以使用-n來忽略換行符
[root@host1 src]# echo abc ddd
abc ddd
[root@host1 src]# echo -n abc ddd
abc ddd[root@host1 src]# 

echo -e

echo -e 處理特殊字符

若字符串中出現以下字符,則特別加以處理,而不會將它當成一般文字輸出:

\a 發出警告聲;
\b 刪除前一個字符;
\c 最后不加上換行符號;
\f 換行但光標仍舊停留在原來的位置;
\n 換行且光標移至行首;
\r 光標移至行首,但不換行;
\t 插入tab;
\v 與\f相同;
\\ 插入\字符;
\nnn 插入nnn(八進制)所代表的ASCII字符;

下面舉例說明一下:

$echo -e "a\bdddd"  //前面的a會被擦除
dddd

$echo -e "a\adddd" //輸出同時會發出報警聲音
adddd

$echo -e "a\ndddd" //自動換行
a
dddd

變量

字符串長度: ${#var}

[root@host1 src]# echo ${NODE_HOME}
/usr/local/node
[root@host1 src]# echo ${#NODE_HOME}
15
#長度有15個字符

使用shell進行數學計算

當使用let時,變量名之前不需要添加$

[root@host1 src]# nod1=3
[root@host1 src]# nod2=5
[root@host1 src]# abc=$[nod1+nod2]
[root@host1 src]# echo $abc
8
[root@host1 src]# let def=nod1+nod2
[root@host1 src]# echo $def
8

bc

[root@host3 2056]# echo "4*0.56" |bc
2.24
[root@host3 2056]# no=54
[root@host3 2056]# res=`echo "$no*1.5"|bc`
[root@host3 2056]# echo $res
81.0
[root@host3 2056]# 

其他參數可以置于要執行的具體操作之前,同時以分號作為定界符,通過stdin傳遞給bc

例如設置小數精度

[root@host3 2056]# echo "scale=2;3/8" | bc
.37

文件描述符

  • 0---stdin 標準輸入
  • 1---stdout 標準輸出
  • 2---stderr 標準錯誤

當一個命令發生錯誤并退出時,她會返回一個非0的退出狀態,執行成功后會返回數字0,。退出狀態可以沖$?中獲得, echo $?

正確輸出到out.txt,錯誤輸出到桌面
ls  > out.txt

錯誤輸出到out.txt,正確輸出到桌面
ls  2> out.txt

所有輸出重定向到out.txt
ls  &> out.txt

可以聯合起來
find /etc -name passwd > find.txt 2> find.err

把錯誤結果丟棄,只輸出正確結果在屏幕
find /etc -name passwd 2> /dev/null

把所有結果丟棄
find /etc -name passwd &> /dev/null

由于錯誤的輸出是不能經過管道的,所以如果必要,必須把錯誤輸出當正確輸出
即:find /etc -name passwd 2>&1 |less

例如find /etc -name passwd |wc -l
實際上這個統計的只有正確的行數,錯誤的輸出沒有統計

find /etc -name passwd 2>&1 |wc -l
這個則把錯誤的也當正確的統計出來了

/sbin/service vsftpd stop > /dev/null 2>&1
意思是停止這個服務,正確的輸出丟棄,錯誤輸出當正確輸出輸出到終端

數組和關聯數組

定義數組的方式有多種,我們常用在單行中只用一列值來定義數組:

[root@host3 ~]# array_var=(1 2 3 4 5 6 6 6)
[root@host3 ~]# echo ${array_var[*]}  #打印數組中所有值,方式1
1 2 3 4 5 6 6 6
[root@host3 ~]# echo ${array_var[@]}  #打印數組中所有值,方式2
1 2 3 4 5 6 6 6
[root@host3 ~]# echo ${#array_var[*]} #打印數組長度
8

關聯數組類似于字典,可以自定義key值,可以列出數組索引key


獲取終端信息

tput sc #存儲光標位置
tput rc #恢復光標
tput ed #清除光標到行尾的所有內容

腳本中生成延時

倒計時:

#!/bin/bash
echo -n Count:
tput sc

count=11;
while true;
do+
  if [ $count -gt 0 ];
  then
    let count--;
    sleep 1;
    tput rc
    tput ed
    echo -n $count;
  else exit 0;
  fi
done

#此處的栗子中,變量count初始值為11,每次循環便減少1,。tput sc存儲光標位置。在每次循環中,通過恢復之前存儲的光標位置,在終端中打印出新的count值。恢復光標位置的命令是tput rc。 tput ed清除從當前光標位置到行尾之間的所有內容,使得舊的count值可以被清除并寫入新值。

函數和參數

  • 定義函數

    function fname()
    {
    statements;
    }
    
    或者:
    
    fname()
    {
    statements;
    }
  • 調用,只需要使用函數名字就能調用

    fname; #執行函數
  • 參數可以傳遞給函數,并有腳本進行訪問

    fname arg1 arg2;
  • 各種訪問函數參數的方法

    fname()
    {
    echo $1,$2; #訪問參數1和參數2
    echo "$@"; #以列表的形式一次打印所有參數
    echo "$*"; #類似于$@,但是參數被作為單個實體
    echo "$#"; #$#表示這個腳本或者函數后面參數的個數
    return 0;  #返回值
    }
    #$@比$*用的多,因為$*把所有參數當做單個字符串,因此很少使用
  • 函數遞歸
    在bash中函數同樣支持遞歸(可以調用自身的函數),例如

    F() { echo $1; F hello; sleep 1; }

    fork炸彈

    :(){ :|:& };:
    
    #這個遞歸函數就能不斷的調用自身,生成新的進程,最終造成拒絕服務***,函數調用前的&將紫禁城放入后臺。這段危險的代碼會分支處大量的進程,因而成為fork炸彈
    
    [root@host3 ~]#  :(){ :|:& };:
    [1] 2526
    [root@host3 ~]# 
    [1]+  完成  
    
    死機了

    這樣看起來不是很好理解,我們可以更改下格式:

    :()
    {
    :|:&
    };
    :

    更好理解一點的話就是這樣:

    bomb()
    {
    bomb|bomb&
    };
    bomb

    因為shell中函數可以省略function關鍵字,所以上面的十三個字符是功能是定義一個函數與調用這個函數,函數的名稱為:,主要的核心代碼是:|:&,可以看出這是一個函數本身的遞歸調用,通過&實現在后臺開啟新進程運行,通過管道實現進程呈幾何形式增長,最后再通過:來調用函數引爆炸彈.因此,幾秒鐘系統就會因為處理不過來太多的進程而死機,解決的唯一辦法就是重啟


預防方式

當然,Fork炸彈沒有那么可怕,用其它語言也可以分分鐘寫出來一個,例如,python版:

  import os
  while True: 
      os.fork()

Fork炸彈的本質無非就是靠創建進程來搶占系統資源,在Linux中,我們可以通過ulimit命令來限制用戶的某些行為,運行ulimit -a可以查看我們能做哪些限制:

[root@host3 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7675
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 655350
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 100
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

可以看到,-u參數可以限制用戶創建進程數,因此,我們可以使用ulimit -u 100來允許用戶最多創建100個進程。這樣就可以預防bomb炸彈。但這樣是不徹底的,關閉終端后這個命令就失效了。我們可以通過修改/etc/security/limits.conf文件來進行更深層次的預防,在文件里添加如下行

*       soft    nproc   100
*       hard    nproc   100
  • 讀取命令返回值(狀態)

    $? 給出命令的返回值

    返回值被成為退出狀態,他可以用來分析命令是否執行成功,如果成功,退出狀態為0,否則非0


將命令序列的輸出讀入變量

  • 利用子shell生成一個獨立的進程

    子shell本來就是一個獨立的進程,可以使用()操作符來定義一個子shell:

pwd;
(cd /bin; ls);
pwd;

#當命令在子shell中運行時,不會對當前的shell有任何影響,所有的改變僅限于子shell內部。例如當cd改變子shell的當前目錄時,這種變化不會反映到主shell環境中

read讀取

read用于從鍵盤或者標準輸入中讀取文本。以交互的形式讀取來自用戶的輸入。
任何變成語言的輸入庫大都是從鍵盤讀取輸入;但只有當回車鍵按下的時候,才標志著輸入完畢。
read提供了一種不需要回車鍵就能搞定這個任務的方法

  • 讀取n個字符并存入變量name
read -p "Enter input:" var
#提示讀取

read -n number_of_chars name

read -n 3 var
echo $var
  • 用特定的定界符作為輸入行的結束
read -d ":" var
echo $var

#以冒號作為輸入行的結束

運行命令直到執行成功

按照以下方式定義函數:

repeat() { while true;do $@ && return; done }

#我們創建了repeat函數,她包含一個無限循環,該循環執行以參數形式(通過$@訪問)傳入函數的命令。如果命令執行成功,則返回,進而退出循環

一種更快的做法:

在大多數現代系統中,true是作為一個二進制文件來實現的。這就意味著沒執行一次while循環,shell就不得不生成一個進程。如果不想這樣,可以使用shell內檢的":"命令,她總是返回為0的退出碼:

repeat() { while :; do $@ && return; done }

#盡管可讀性不高,但是肯定比上一種方法快

增加延時

屁如,你要從internet上下一個暫時不可用的文件,不過這個文件需要等一段時間就能下載。方法如下:

repeat wget -c http://abc.test.com/software.tar.gz

#如果采用這種形式,需要向服務器發送很多數據,可能對服務器產生影響,我們可以修改函數,加入一段短暫的延時

repeat() { while :; do $@ && return; sleep30; done }

#這使得命令每30秒運行一次

字段分隔符和迭代器

內部字段分隔符IFS是shell腳本中的一個重要概念。他是存儲界定符的環境變量,是當前shell環境中使用的默認存在的認定界字符串

IFS的默認值為空白字符(換行符,制表符,或者空格)如在shell中默認以空格符作為IFS

[root@host3 ~]# data="abc eee ddd fff"
[root@host3 ~]# for item in $data; do echo ITEM: $item; done
ITEM: abc
ITEM: eee
ITEM: ddd
ITEM: fff

執行:
list1="1 2 3 3 4 4"
for line in $list1
do
echo $line;
done

輸出:
1
2
3
3
4
4

執行:
for line in 1 2 3 3 4 4 #如果將in后面的用引號引起來,就會當成一個字符串
do
echo $line;
done

同樣輸出:
1
2
3
3
4
4

接下來我們可以將IFS改成逗號:

#沒有修改IFS,此時我們默認是空格符,故將data作為單個字符串打印出來
[root@host3 ~]# data="eee,eee,111,222"
[root@host3 ~]# for item in $data1; do echo ITEM: $item; done
ITEM: eee,eee,111,222
[root@host3 ~]# oldIFS=$IFS  #此步驟是為了先備份目前的IFS為oldIFS,后面會恢復
[root@host3 ~]# IFS=,  #備份后修改IFS為逗號,再次輸出則發現逗號已經成為分隔符
[root@host3 ~]# for item in $data1; do echo ITEM: $item; done
ITEM: eee
ITEM: eee
ITEM: 111
ITEM: 222
[root@host3 ~]# IFS=$oldIFS #還原IFS為原來的
[root@host3 ~]# for item in $data1; do echo ITEM: $item; done
ITEM: eee,eee,111,222

故我們再修改了IFS使用之后記得恢復到原樣


for循環

for var in list;
do
  commands;
done

list可以是一個字符串,也可以是一個序列
{1..50}生成一個1-50的數字列表
{a..z}或{A..Z}或{a..h}生成字母表

for也可以采用c語言中的for循環模式

for (i=0;i<10;i++)
{
  commands; #使用變量$i
}

while循環

while condition
do
  commands;
done

until循環

她會一直循環直到給出的條件為真

x=0;
until [ $x -eq 9 ];
do
  let x++; echo $x;
done

比較與測試

程序中的流程控制是比較語句和測試語句處理的。我們可以用if if else以及邏輯運算符進行測試,用比較運算符來比較數據。除此之外,還有一個test命令也用于測試

if condition;
then
  commands;
fi

if condition;
then
  commands;
else if condition; then
  commands;
else
  commands;
fi

if和else語句可以進行嵌套,那樣會變得很長,可以用邏輯運算符將他簡潔點

[ condition ] && action; #如果前者為真,則執行action;
[ condition ] || action; #如果前者為假,則執行action;

算術比較

條件通常被放置在封閉的中括號內,一定注意在 [或]與操作數之間有一個空格,如果忘記了這個空格,就會報錯

算術判斷:

[ $var -eq 0 ] #當$var等于0時,返回真
[ $var -ne 0 ] #當$var為非0時,返回真

其他:
-gt: 大于
-lt:小于
-ge:大于或等于
-le:小于或等于

多條件測試:
[ $var1 -ne 0 -a $var2 -gt 2 ] #邏輯與 -a
[ $var1 -ne 0 -o $var2 -gt 2 ] #邏輯或 -o

文件系統相關測試

我們可以使用不同的條件標志測試不同的文件系統相關的屬性:

[ -f file ] 給定的變量包含正常的文件路徑或文件名,則為真
[ -x file ] 可執行,為真
[ -d file ] 是目錄,為真
[ -e file ] 文件存在,則為真
[ -w file ] 可寫,則為真
[ -r file ] 可讀,則為真
[ -L file ] 包含的是一個符號鏈接,則為真

使用方法如下:

fpath="/etc/passwd"
if [ -e $fpath ];then
  echo File exists;
else
  echo Dose not exists;
fi

字符串比較

使用字符串比較時,最好用雙中括號,因為有時候采用單個中括號會產生錯誤,所以最好避開

可以使用下面的方法測試兩個字符串,看看是否相同

[[ $str1 = $str2 ]]
或者:
[[ $str1 == $str2 ]]
反之:
[[ $str1 != $str2 ]]

[[ -z $str1 ]] 為空字符串,則返回真
[[ -n $str1 ]] 為非空字符串,則返回真
  • 注意在=前后均有一個空格,如果忘記空格,那就不是比較關系,而是賦值語句
  • 使用邏輯&& 和 ||能夠比較容易將多個條件組合起來

cat

一般寫法:

逆序打印命令tac,這個和cat相反

cat file1 file2 file3 ...
這個命令將命令行參數的文件內容拼接在一起

類似的,我們可以用cat將來自輸入文件的內容與標準輸入拼接到一起,將stdin和另外一個文件中的數據結合起來,方法如下:

echo "111111" |cat  - /etc/passwd
上面的代碼中,-被作為stdin文本的文件名
將制表符顯示為^I

例如在用python編寫程序時,代碼縮進用制表符和空格是不同的,如果在空格的地方使用了制表符,就會發生縮進錯誤。僅僅在文本編輯器中很難發現這種錯誤

此時,我們可以用-T選項顯示出制表符,標記成 ^I

[root@host3 ~]# cat bbb.sh 
for line in "1 2 3 3 4 4"
do
    echo $line;
done

[root@host3 ~]# cat -T bbb.sh 
for line in "1 2 3 3 4 4"
do
^Iecho $line;
done

行號 cat -n

#-n會為空白行也加上行號,如果需要跳過空白行,那么可以使用選項-b

[root@host3 ~]# cat bbb.sh 
for line in "1 2 3 3 4 4"

do
    echo $line;
done
[root@host3 ~]# cat -n bbb.sh 
     1  for line in "1 2 3 3 4 4"
     2  
     3  do
     4      echo $line;
     5  done
[root@host3 ~]# cat -b bbb.sh 
     1  for line in "1 2 3 3 4 4"

     2  do
     3      echo $line;
     4  done

find

find 命令的工作方式是,沿著文件層次結構向下遍歷,匹配符合條件的文件,執行相應操作

find /etc #列出目錄下所有的文件和文件夾,包括隱藏文件

find -iname 忽略大小寫

#匹配一個或者多個文件時候,可以用OR條件操作,如查找/etc下所有.txt和.conf文件
find /etc  \( -name "*.txt" -o -name "*.conf" \) 
find /etc  \( -name "*.txt" -o -name "*.conf" \) -print
#\(以及\)用于將-name "*.txt" -o -name "*.conf"視為一個整體

#-name用來匹配文件,-path則用來匹配文件路徑,可用通配符
find  / -path "*/etc/*" -print
#打印只要路徑中包含/etc/的及打印

#-regex參數,正則則更加強大。例如email地址可以常用name@host.root這種形式。所以將其一般轉化為:
#[a-z0-9]+@[a-z0-9]+.[a-z0-9]+
#符號+指明在它之前的字符類中字符可以出現一次或者多次。
find /etc -regex ".*\(\.py|\.sh\)$"
#查找以.py或.sh結尾的所有文件
#同樣 -iregex也可以忽略大小寫,同-iname一樣

#-regex同樣屬于測試項。使用-regex時有一點要注意:-regex不是匹配文件名,而是匹配完整的文件名(包括路徑)。例如,當前目錄下有一個文件"abar9",如果你用"ab.*9"來匹配,將查找不到任何結果,正確的方法是使用".*ab.*9"或者".*/ab.*9"來匹配。

find . -regex ".*/[0-9]*/.c" -print

否定參數

find /etc ! -name "*.conf" -print

基于目錄深度的搜索

我們可以采用深度選項 -maxdepth和-mindepth來限制find命令遍歷的目錄深度

[root@host3 ~]# find /etc -maxdepth 1 -name "*.conf" -print
/etc/resolv.conf
/etc/dracut.conf
/etc/host.conf

[root@host3 ~]# find /etc -maxdepth 2 -name "*.conf" -print
/etc/resolv.conf
/etc/depmod.d/dist.conf

[root@host3 ~]# find /etc -mindepth 4 -name "*.conf" -print
/etc/openldap/slapd.d/openldap/ldap.conf
/etc/openldap/slapd.d/openldap/schema/schema_convert.conf
/etc/openldap/slapd.d/openldap/slapd.conf

基于時間的進行搜索

-atime:最近一次訪問時間
-mtime:最近一次修改時間
-ctime:文件元數據(例如權限或者所有權)最后一次改變時間
上面都是以天為單位
也有以分鐘為單位:
-amin
-mmin
-cmin

-newer,參考文件,比較時間戳。比參考文件更新的文件
[root@host3 ~]# find /etc -type f -newer /etc/passwd -print
/etc/resolv.conf
/etc/shadow
/etc/ld.so.cache
/etc/cni/net.d/calico-kubeconfig

基于文件大小的搜索

find /etc -type f -size +2k  #大于2k
find /etc -type f -size -2k  #小于2k
find /etc -type f -size 2k  #等于2k

刪除匹配的文件

find ./ -type f -name "*.txt" -delete

基于文件和所有權

find /etc -type f -perm 644

find /etc -type f -name "*.conf"  ! -perm 644

基于用戶進行搜索

find /etc -type f -user USER

執行命令或者動作

find /etc -type f -user root -exec chown mysql {} \;
#將所有所有人是root的文件所有人改成mysql

# {}是一個和-exec選項搭配使用的特殊字符串。對于每一個匹配文件, {}會被替換成相應的文件名。

另外一個例子就是將給定目錄中的所有文件內容拼接起來寫入單個文件,我們可以用find找到所有.conf文件,然后結合-exec使用cat命令:

find /etc/ -type f -name "*.conf" -exec cat {} \;>all.txt
#即將所有.conf文件的內容全部追加寫入all.txt文件里
#沒有用>>追加的原因是因為find命令全部輸出就只有一個數據流(stdin),而只有當多個數據流被追加到單個文件時才有必要使用

#下面命令將10天前的.txt文件復制到OLD目錄:
find /etc -type f -mtime +10 -name "*.txt" -exec cp {} OLD \;

讓find跳過一些目錄

有時候為了提高性能,需要跳過一些目錄,例如git,每個子目錄中都會包含一個.git目錄,要跳過這些目。

find /etc \( -name ".git" -prune \) -o \( -type f -print  \)

#\( -name "/etc/rabbitmq" -prune \)的作用是用于排除,而\( -type f -print  \)指明需要執行的動作。

玩轉xargs

xargs命令把從stdin接收到的數據重新格式化,再將其作為參數提供給其他命令

xargs作為一種替代,其作用類似于find命令中的-exec

  • 將多行輸入轉換成單行輸出,只要將換行符移除,再用空格進行替代,就可以實現多行輸入轉換。利用xargs,我們可以用空格替換掉換行符,這樣就能夠將多行轉換成單行
[root@host3 ~]# cat 123.txt 
1 2 3 4 5
6 7 8 9
10 11 12 13 14

[root@host3 ~]# cat 123.txt |xargs
1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • 將單行輸入轉換成多行輸出,指定每行最大的參數數量n,我們可以將任何來自stdin的文本劃分為多行,每行n個參數。每個參數有空格隔開的字符串。空格是默認的界定符。
[root@host3 ~]# cat 123.txt 
1 2 3 4 5
6 7 8 9
10 11 12 13 14

[root@host3 ~]# cat 123.txt |xargs -n 3
1 2 3
4 5 6
7 8 9
10 11 12
13 14

[root@host3 ~]# echo  1 3 4 5 6 7 8 |xargs -n 3
1 3 4
5 6 7
8
  • 自定義界定符來分割參數。用-d選項為輸入指定一個定制的界定符
[root@host3 ~]# echo "abcTdslfjTdshfsT1111Tfd222" |xargs -d T
abc dslfj dshfs 1111 fd222
#以字母T作為分隔符

#我們可以自定義分解符的同時每行定義輸出多少個參數
[root@host3 ~]# echo "abcTdslfjTdshfsT1111Tfd222" |xargs -d T -n 2
abc dslfj
dshfs 1111
fd222

#每行輸出一個參數
[root@host3 ~]# echo "abcTdslfjTdshfsT1111Tfd222" |xargs -d T -n 1
abc
dslfj
dshfs
1111
fd222
  • 子shell

cmd0 | (cmd1;cmd2;cmd3) | cmd4

中間是子shell,里面如果有cmd,只在子shell內生效


print和print0的區別

-print 在每一個輸出后會添加一個回車換行符,而-print0則不會。
[root@AaronWong shell_test]# find /home/AaronWong/ABC/ -type f -print
/home/AaronWong/ABC/libcvaux.so
/home/AaronWong/ABC/libgomp.so.1
/home/AaronWong/ABC/libcvaux.so.4
/home/AaronWong/ABC/libcv.so
/home/AaronWong/ABC/libhighgui.so.4
/home/AaronWong/ABC/libcxcore.so
/home/AaronWong/ABC/libhighgui.so
/home/AaronWong/ABC/libcxcore.so.4
/home/AaronWong/ABC/libcv.so.4
/home/AaronWong/ABC/libgomp.so
/home/AaronWong/ABC/libz.so
/home/AaronWong/ABC/libz.so.1
[root@AaronWong shell_test]# find /home/AaronWong/ABC/ -type f -print0
/home/AaronWong/ABC/libcvaux.so/home/AaronWong/ABC/libgomp.so.1/home/AaronWong/ABC/libcvaux.so.4/home/AaronWong/ABC/libcv.so/home/AaronWong/ABC/libhighgui.so.4/home/AaronWong/ABC/libcxcore.so/home/AaronWong/ABC/libhighgui.so/home/AaronWong/ABC/libcxcore.so.4/home/AaronWong/ABC/libcv.so.4/home/AaronWong/ABC/libgomp.so/home/AaronWong/ABC/libz.so/home/AaronWong/ABC/libz.so.1

tr

tr只能通過stdin標準輸入,而無法通過命令行參數來接收輸入。他的調用格式為:

tr [option] set1 set2

制表符轉換成空格: tr '\t' ' ' < file.txt

[root@host3 ~]# cat -T 123.txt 
1 2 3 4 5
6 7 8 9
^I10 11 12 13 14

[root@host3 ~]# tr '\t' '    ' < 123.txt 
1 2 3 4 5
6 7 8 9
 10 11 12 13 14
  • 用tr刪除字符

tr有一個選項-d,可以通過指定需要被刪除的字符集合,將出現在stdin中的特定字符清除掉:

cat  file.txt |tr -d '[set1]'
#只使用set1不使用set2

#替換數字
[root@host3 ~]# echo "Hello 123 world 456" |tr -d '0-9'
Hello  world 

#替換字母
[root@host3 ~]# echo "Hello 123 world 456" |tr -d 'A-Za-z'
 123  456

#替換H
[root@host3 ~]# echo "Hello 123 world 456" |tr -d 'H'
ello 123 world 456

排序,唯一與重復

sort能幫助我們對文本文件和stdin進行排序操作。他通常配合其他命令來生成所需要的輸出。uniq是一個經常與sort一同使用的命令。他的作用是從文本或stdin中提取唯一的行。

#我們可以按照下面的方式輕松的對一組文件(例如file1.txt file2.txt)進行排序:
[root@host3 ~]# sort /etc/passwd /etc/group 
adm:x:3:4:adm:/var/adm:/sbin/nologin
adm:x:4:
apache:x:48:
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
audio:x:63:
bin:x:1:
bin:x:1:1:bin:/bin:/sbin/nologin
caddy:x:996:
caddy:x:997:996:Caddy web server:/var/lib/caddy:/sbin/nologin
...

#也可合并排序后重定向到新文件
sort /etc/passwd /etc/group > abc.txt

#按照數字排序
sort -n

#逆序排序
sort -r

#按照月份排序
sort -M month.txt

#合并兩個已經排序了的文件
sort -m sorted1 sorted2

#找出已排序文件中不重復的行
sort file1.txt file2.txt |uniq

檢查文件是否已經排序過:

要檢查文件是否排過序,可以采用以下方法,如果已經排序,sort會返回0的退出碼($?),否則返回非0

#!/bin/bash
sort -C filename;
if [ $? -eq 0 ]; then
  echo Sorted;
else
  echo Unsorted;
fi

sort命令包含大量選項。如果使用uniq,那sort更加必不可少,因為需求輸入數據必須經過排序

sort完成一些較復雜的任務

#-k指定了按照哪一列進行排序,-r逆序,-n按照數字
sort -nrk 1 data.txt
sort -k 2 data.txt

uniq

uniq只能作用于排過序的數據輸入

[root@host3 ~]# cat data.txt 
1010hellothis
3333
  2189ababbba
333
 7464dfddfdfd
333

#去重
[root@host3 ~]# sort data.txt |uniq
1010hellothis
  2189ababbba
333
3333
 7464dfddfdfd

#去重并統計
[root@host3 ~]# sort data.txt |uniq -c
      1 1010hellothis
      1   2189ababbba
      2 333
      1 3333
      1  7464dfddfdfd

#只顯示文本中沒有重復的行
[root@host3 ~]# sort data.txt |uniq -u
1010hellothis
  2189ababbba
3333
 7464dfddfdfd

#只顯示文本中重復了的行
[root@host3 ~]# sort data.txt |uniq -d
333

臨時文件命名和隨機數

編寫shell腳本時,我們經常需要存儲臨時數據。最適合存儲臨時數據的位置是/tmp(該目錄中的內容在系統重啟后會被清空)。有兩種方法可以為臨時數據生成標準的文件名

[root@host3 ~]# file1=`mktemp`
[root@host3 ~]# echo $file1
/tmp/tmp.P9var0Jjdw
[root@host3 ~]# cd /tmp/
[root@host3 tmp]# ls
add_user_ldapsync.ldif     create_module_config.ldif.bak   globalconfig.ldif       overlay.ldif
create_module_config.ldif  databaseconfig_nosyncrepl.ldif  initial_structure.ldif  tmp.P9var0Jjdw
#上面的代碼創建了一個臨時文件,并且打印出文件名

[root@host3 tmp]# dir1=`mktemp -d`
[root@host3 tmp]# echo $dir1
/tmp/tmp.UqEfHa389N
[root@host3 tmp]# ll
總用量 28
-r--------. 1 root root  130 2月  12 2019 add_user_ldapsync.ldif
-r--------. 1 root root  329 2月  14 2019 create_module_config.ldif
-r--------. 1 root root  329 2月  12 2019 create_module_config.ldif.bak
-r--------. 1 root root 2458 2月  14 2019 databaseconfig_nosyncrepl.ldif
-r--------. 1 root root  239 2月  12 2019 globalconfig.ldif
-r--------. 1 root root  795 2月  12 2019 initial_structure.ldif
-r--------. 1 root root  143 2月  12 2019 overlay.ldif
-rw-------  1 root root    0 9月  27 13:06 tmp.P9var0Jjdw
drwx------  2 root root    6 9月  27 13:09 tmp.UqEfHa389N
#以上代碼創建了一個臨時目錄,并打印目錄名

[root@host3 tmp]# mktemp test1.XXX
test1.mBX
[root@host3 tmp]# mktemp test1.XXX
test1.wj1
[root@host3 tmp]# ls
總用量 28
-r--------. 1 root root  130 2月  12 2019 add_user_ldapsync.ldif
-r--------. 1 root root  329 2月  14 2019 create_module_config.ldif
-r--------. 1 root root  329 2月  12 2019 create_module_config.ldif.bak
-r--------. 1 root root 2458 2月  14 2019 databaseconfig_nosyncrepl.ldif
-r--------. 1 root root  239 2月  12 2019 globalconfig.ldif
-r--------. 1 root root  795 2月  12 2019 initial_structure.ldif
-r--------. 1 root root  143 2月  12 2019 overlay.ldif
-rw-------  1 root root    0 9月  27 13:12 test1.mBX
-rw-------  1 root root    0 9月  27 13:12 test1.wj1
-rw-------  1 root root    0 9月  27 13:06 tmp.P9var0Jjdw
drwx------  2 root root    6 9月  27 13:09 tmp.UqEfHa389N
#以上是根據模板名創建臨時文件,XXX為大寫,X會被隨機的字符字母或者數字替換,注意mktemp正常工作的前提是保證模板中至少有3個X

分割文件和數據split

假設一個data.txt的測試文件,大小為100kb,你可以將他分割為多個大小為10kb的文件

[root@host3 src]# ls
nginx-1.14.2  nginx-1.14.2.tar.gz
[root@host3 src]# du -sh nginx-1.14.2.tar.gz 
992K    nginx-1.14.2.tar.gz
[root@host3 src]# split -b 100k nginx-1.14.2.tar.gz 
[root@host3 src]# ll
×üó?á? 1984
drwxr-xr-x 9 postgres mysql     186 8??  15 19:50 nginx-1.14.2
-rw-r--r-- 1 root     root  1015384 8??  16 10:44 nginx-1.14.2.tar.gz
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xaa
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xab
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xac
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xad
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xae
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xaf
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xag
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xah
-rw-r--r-- 1 root     root   102400 9??  29 12:36 xai
-rw-r--r-- 1 root     root    93784 9??  29 12:36 xaj
[root@host3 src]# ls
nginx-1.14.2  nginx-1.14.2.tar.gz  xaa  xab  xac  xad  xae  xaf  xag  xah  xai  xaj
[root@host3 src]# du -sh *
32M nginx-1.14.2
992K    nginx-1.14.2.tar.gz
100K    xaa
100K    xab
100K    xac
100K    xad
100K    xae
100K    xaf
100K    xag
100K    xah
100K    xai
92K xaj
#如上,將992K的nginx tar包分成了100k一個,最后不足100k只有92k

由上面的可以看出來,默認是以字母為后綴。如果想以數字為后綴,可以使用-d參數,-a length指定后綴長度

[root@host3 src]# ls
nginx-1.14.2  nginx-1.14.2.tar.gz
[root@host3 src]# split -b 100k nginx-1.14.2.tar.gz -d -a 5
[root@host3 src]# ls
nginx-1.14.2  nginx-1.14.2.tar.gz  x00000  x00001  x00002  x00003  x00004  x00005  x00006  x00007  x00008  x00009
[root@host3 src]# du -sh *
32M nginx-1.14.2
992K    nginx-1.14.2.tar.gz
100K    x00000
100K    x00001
100K    x00002
100K    x00003
100K    x00004
100K    x00005
100K    x00006
100K    x00007
100K    x00008
92K x00009
#文件名為x后綴為5位數數字

指定文件名前綴

之前分割的文件,文件都有一個文件名x,我們也可以通過前綴名來使用自己的文件前綴。split命令最后一個參數是PREFIX

[root@host3 src]# ls
nginx-1.14.2  nginx-1.14.2.tar.gz
[root@host3 src]# split -b 100k nginx-1.14.2.tar.gz -d -a 4 nginxfuck
[root@host3 src]# ls
nginx-1.14.2         nginxfuck0000  nginxfuck0002  nginxfuck0004  nginxfuck0006  nginxfuck0008
nginx-1.14.2.tar.gz  nginxfuck0001  nginxfuck0003  nginxfuck0005  nginxfuck0007  nginxfuck0009
#如上,最后一個參數指定了前綴

如果不想根據大小來分割,我們可以根據行數來分割-l

[root@host3 test]# ls
data.txt
[root@host3 test]# wc -l data.txt 
7474 data.txt
[root@host3 test]# split -l 1000 data.txt -d -a 4 conf
[root@host3 test]# ls
conf0000  conf0001  conf0002  conf0003  conf0004  conf0005  conf0006  conf0007  data.txt
[root@host3 test]# du -sh *
40K conf0000
48K conf0001
48K conf0002
36K conf0003
36K conf0004
36K conf0005
36K conf0006
20K conf0007
288K    data.txt
#以上將一個7000行的文件分成1000行一份,文件名以conf開頭,后接4位數字

文件分割csplit

csplit能依據指定的條件和字符串匹配選項對日志文件進行分割,是split工具的一個變體

split只能根據數據的大小和行數進行分割,而csplit可以根據文件自身的特點進行分割。是否存在某個單詞或文本內容都可以作為分割文件的條件

[root@host3 test]# ls
data.txt
[root@host3 test]# cat data.txt 
SERVER-1
[conection] 192.168.0.1 success
[conection] 192.168.0.2 failed
[conection] 192.168.0.3 success
[conection] 192.168.0.4 success
SERVER-2
[conection] 192.168.0.5 success
[conection] 192.168.0.5 failed
[conection] 192.168.0.5 success
[conection] 192.168.0.5 success
SERVER-3
[conection] 192.168.0.6 success
[conection] 192.168.0.7 failed
[conection] 192.168.0.8 success
[conection] 192.168.0.9 success
[root@host3 test]# csplit data.txt /SERVER/ -n 2 -s {*} -f server -b "%02d.log";rm server00.log
rm:是否刪除普通空文件 "server00.log"?y
[root@host3 test]# ls
data.txt  server01.log  server02.log  server03.log

詳細說明:

  • /SERVER/ 用來匹配行,分割過程即從此處開始
  • /[REGEX]/ 表示文本樣式。包括從當前行(第一行)知道(但不包括)包含“SERVER”的匹配行
  • {*} 表示根據匹配行重復執行分割,直到文件末尾位置。可以用{整數}的形式來指定分割的次數
  • -s 使命令進入靜默模式,不打印其他消息。
  • -n指定分割后的文件前綴
  • -b指定后綴格式,例如%02d.log,類似于C語言中的printf.

因為分割后的第一個文件沒有任何內容(匹配的單詞就位于文件的第一行),所以我們刪除server00.log


根據擴展名切分文件名

有一些腳本時依據文件名進行各種處理的,我們可能需要在保留擴展名的同時修改文件名,轉換文件格式(保留文件名的同時修改擴展名)或提取部分文件名。shell所具有的一些內建功能可以依據不同的情況來切分文件名

借助%符號可以輕松將名稱部分從"名稱.擴展名"這種格式中提取出來。

[root@host3 ~]# file_jpg="test.jpg"
[root@host3 ~]# name=${file_jpg%.*}
[root@host3 ~]# echo $name
test
#即提取了文件名部分

借助#符號則可以將文件名的擴展名部分提取出來。

[root@host3 ~]# file_jpg="test.jpg"
[root@host3 ~]# exten=${file_jpg#*.}
[root@host3 ~]# echo $exten
jpg
#提取擴展名,上面提取文件名部分是.* 此處提取擴展名為*.

以上語法釋義

${VAR%.*}含義:

  • 從$VAR中刪除位于%右側的通配符所匹配的字符串,通配符從右向左匹配
  • 給VAR賦值,VAR=test.jpg 那么通配符從右向左就會匹配到.jpg。因此,從$VAR中刪除匹配結果,就會得到test

%屬于非貪婪(non-greedy)操作,他從右到左找出匹配通配符的最短結果。還有另一個操作符%%,這個操作符與%相似,但行為模式卻是貪婪的,這意味著她會匹配符合條件的最長的字符串,例如VAR=hack.fun.book.txt

使用%操作符:
[root@host3 ~]# VAR=hack.fun.book.txt
[root@host3 ~]# echo ${VAR%.*}
hack.fun.book

使用%%操作符:
[root@host3 ~]# echo ${VAR%%.*}
hack

同樣,對于#操作符也有##

使用#操作符:
[root@host3 ~]# echo ${VAR#*.}
fun.book.txt

使用##操作符
[root@host3 ~]# echo ${VAR##*.}
txt

批量重命名和移動

綜合運用find,rename,mv我們能做到很多事情

用特定的格式重命名當前目錄下的圖像文件,最簡單的方法就是運用以下的腳本

#!/bin/bash
count=1;
for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1`
do
  new=image-$count.${img##*.}
  echo "Rename $img to $new"
  mv $img $new
  let count++
done

執行上面腳本

[root@host3 ~]# ll
總用量 24
-rw-r--r--  1 root root    0 10月  8 14:22 aaaaaa.jpg
-rw-r--r--  1 root root  190 8月   9 13:51 aaa.sh
-rw-r--r--  1 root root 2168 9月  24 10:15 abc.txt
-rw-r--r--  1 root root 3352 9月  20 09:58 all.txt
-rw-------. 1 root root 1228 1月   8 2019 anaconda-ks.cfg
-rw-r--r--  1 root root    0 10月  8 14:22 bbbb.jpg
-rw-r--r--  1 root root   48 9月  18 10:27 bbb.sh
-rw-r--r--  1 root root    0 10月  8 14:22 cccc.png
drwxr-xr-x  2 root root  333 4月  11 19:21 conf
-rw-r--r--  1 root root    0 10月  8 14:22 dddd.png
-rw-r--r--  1 root root  190 10月  8 14:22 rename.sh
[root@host3 ~]# sh rename.sh
find: 警告: 您在非選項參數 -iname 后定義了 -maxdepth 選項,但選項不是位置選項 (-maxdepth 影響在它之前或之后的指定的比較測試)。請在其它參數之前指定選項。

Rename ./aaaaaa.jpg to image-1.jpg
Rename ./bbbb.jpg to image-2.jpg
Rename ./cccc.png to image-3.png
Rename ./dddd.png to image-4.png
[root@host3 ~]# ls
aaa.sh  abc.txt  all.txt  anaconda-ks.cfg  bbb.sh  conf  image-1.jpg  image-2.jpg  image-3.png  image-4.png  rename.sh

交互輸入自動化

先寫一個讀取交互式輸入的腳本

#!/bin/bash
#文件名: test.sh
read -p "Enter number:" no
read -p "Enter name:" name
echo $no,$name

按照下面的方法自動向腳本發送輸入:

[root@host3 ~]# ./test.sh 
Enter number:2
Enter name:rong
2,rong
[root@host3 ~]# echo -e "2\nrong\n" |./test.sh  
2,rong

# \n代表著回車,我們用echo -e來生成輸入序列,-e表明echo會解釋轉義序列。如果輸入內容較多,那么可以單獨的輸入文件結合重定向操作符來提供輸入,如下:
[root@host3 ~]# echo -e "2\nrong\n" > input.data
[root@host3 ~]# cat input.data 
2
rong

[root@host3 ~]# ./test.sh < input.data 
2,rong

#這個方法是從文件中導入交互式輸入數據

如果你是逆向工程師,那可能同緩沖區溢出打過交道。要實施,我們需要將十六進制形式的shellcode(例如"\xeb\x1a\x5e\x31\xc0\x88\x46")進行重定向。這些字符沒法直接通過鍵盤輸入,因為鍵盤上并沒有對應的按鍵。因此我們應該使用:

echo -e "\xeb\x1a\x5e\x31\xc0\x88\x46"

用這條命令將shellcode重定向到有缺陷的可執行文件中,為了處理動態輸入并通過檢查程序運行時的輸入需求內容來提供輸入內容,我們要使用一個出色的工具expect。

expect命令可以根據輸入要求提供合適的輸入

用expect實現自動化

在默認的linux發行版中,多數不包含expect,你得自行安裝 :yum -y install expect

#!/usr/bin/expect
# 文件名expect.sh
spawn ./test.sh
expect "Enter number:"
send "2\n"
expect "Enter name:"
send "rong\n"
expect eof

#執行
[root@host3 ~]# ./expect.sh 
spawn ./test.sh
Enter number:2
Enter name:rong
2,rong
  • spawn參數指定需要執行哪個命令或者腳本
  • expect參數提供需要等待的消息
  • send是要發送的消息
  • expect eof指明命令交互結束

利用并行進程加速命令執行

拿md5sum命令為例。由于涉及運算,該命令屬于cpu密集型命令。如果多個文件需要生成校驗和,我們可以使用下面的腳本來運行。

#!/bin/bash
PIDARRAY=()
for file in `find /etc/ -name "*.conf"`
do
  md5sum $file &
  PIDARRAY+=("$!")
done
wait ${PIDARRAY[@]}

執行:
[root@host3 ~]# sh expect.sh 
72688131394bcce818f818e2bae98846  /etc/modprobe.d/tuned.conf
77304062b81bc20cffce814ff6bf8ed5  /etc/modprobe.d/firewalld-sysctls.conf
649f5bf7c0c766969e40b54949a06866  /etc/dracut.conf
d0f5f705846350b43033834f51c9135c  /etc/prelink.conf.d/nss-softokn-prelink.conf
0335aabf8106f29f6857d74c98697542  /etc/prelink.conf.d/fipscheck.conf
0b501d6d547fa5bb989b9cb877fee8cb  /etc/modprobe.d/dccp-blacklist.conf
d779db0cc6135e09b4d146ca69d39c2b  /etc/rsyslog.d/listen.conf
4eaff8c463f8c4b6d68d7a7237ba862c  /etc/resolv.conf
321ec6fd36bce09ed68b854270b9136c  /etc/prelink.conf.d/grub2.conf
3a6a059e04b951923f6d83b7ed327e0e  /etc/depmod.d/dist.conf
7cb6c9cab8ec511882e0e05fceb87e45  /etc/systemd/bootchart.conf
2ad769b57d77224f7a460141e3f94258  /etc/systemd/coredump.conf
f55c94d000b5d62b5f06d38852977dd1  /etc/dbus-1/system.d/org.freedesktop.hostname1.conf
7e2c094c5009f9ec2748dce92f2209bd  /etc/dbus-1/system.d/org.freedesktop.import1.conf
5893ab03e7e96aa3759baceb4dd04190  /etc/dbus-1/system.d/org.freedesktop.locale1.conf
f0c4b315298d5d687e04183ca2e36079  /etc/dbus-1/system.d/org.freedesktop.login1.conf
···

#由于是多個md5sum命令同時運行的,如果你使用的是多核處理器,就會更快的活的運行結果

工作原理:

利用bash的操作符&,它使得shell將命令放置于后臺并繼續執行腳本。這意味著一旦循環結束,腳本就會退出,而md5sum命令仍然在后臺運行。為了避免這種情況,我們使用$!來獲取進程pid,在bash中$!保存這最近一個后臺進程的pid,我們將這些pid放入數組,然后用wait命令等待這些進程結束。


文本文件的交集和差集

comm命令可以用于兩個文件之間的比較

  • 交集: 打印出兩個文件共有的行
  • 求差: 打印出指定文件所包含的且互不相同的行
  • 差集: 打印出包含在文件a中,但不包含在其他文件中的行

需要注意的是,comm必須使用排過序的文件作為輸出

[root@host3 ~]# cat a.txt 
apple
orange
gold
silver
steel
iron
[root@host3 ~]# cat b.txt 
orange
gold
cookies
carrot
[root@host3 ~]# sort a.txt -o A.txt
[root@host3 ~]# vim A.txt 
[root@host3 ~]# sort b.txt -o B.txt
[root@host3 ~]# comm A.txt B.txt 
apple
      carrot
      cookies
              gold
iron
              orange
silver
steel
#可以看出結果是3列,第一列輸出只在A.txt中存在的行,第二列輸出只在B.txt中出現的行,第三列包含A.txt和B.txt中都存在的行,各列以制表符(\t)作為界定符

#為了打贏交集,我們需要刪除第一列和第二列,只顯示第三列
[root@host3 ~]# comm A.txt B.txt -1 -2
gold
orange

#只打印不同
[root@host3 ~]# comm A.txt B.txt -3
apple
      carrot
      cookies
iron            
silver
steel

#為了是結果可讀性強,去掉前面的\t制表符
[root@host3 ~]# comm A.txt B.txt -3 |sed 's/^\t//'
apple
carrot
cookies
iron
silver
steel

創建不可修改的文件

使文件設置為不可修改 chattr +i file

[root@host3 ~]# chattr +i passwd 
[root@host3 ~]# rm -rf passwd 
rm: 無法刪除"passwd": 不允許的操作
[root@host3 ~]# chattr -i passwd 
[root@host3 ~]# rm -rf passwd 
[root@host3 ~]# 

grep

grep可以對多個文件進行搜索

[root@host3 ~]# grep root /etc/passwd /etc/group
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
/etc/passwd:dockerroot:x:996:994:Docker User:/var/lib/docker:/sbin/nologin
/etc/group:root:x:0:
/etc/group:dockerroot:x:994:

grep命令只解釋match_text中的某些特殊字符。如果要使用正則表達式,需要添加 -E選項。這意味著使用擴展正則表達式。或者也可以使用默認允許正則表達式的egrep命令(經過實測不加-E也可以)

#統計文本中包含匹配字符串的行數
[root@host3 ~]# grep -c root /etc/passwd
3

#打印行號
[root@host3 ~]# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
27:dockerroot:x:996:994:Docker User:/var/lib/docker:/sbin/nologin

#搜索多個文件并找出匹配文本位于哪一個文件中-l
[root@host3 ~]# grep root /etc/passwd /etc/group
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
/etc/passwd:dockerroot:x:996:994:Docker User:/var/lib/docker:/sbin/nologin
/etc/group:root:x:0:
/etc/group:dockerroot:x:994:

[root@host3 ~]# grep root /etc/passwd /etc/group -l
/etc/passwd
/etc/group

#-L則正好相反 ,會列出不匹配的文件名

#忽略大小寫 -i
#多個樣式匹配-e
grep -e "pattern1" -e "pattern2"  #匹配包含模式1或者模式2的

[root@host3 ~]# grep -e root -e docker /etc/passwd /etc/group
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
/etc/passwd:dockerroot:x:996:994:Docker User:/var/lib/docker:/sbin/nologin
/etc/group:root:x:0:
/etc/group:dockerroot:x:994:
/etc/group:docker:x:992:

#還有另外一種方法也可以指定多個樣式,我們可以提供一個樣式條件用于讀取樣式。用-f指定文件,注意pat.file文件中不要包含末尾的空白行等
[root@host3 ~]# cat pat.file 
root
docker
[root@host3 ~]# grep -f pat.file /etc/passwd /etc/group
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
/etc/passwd:dockerroot:x:996:994:Docker User:/var/lib/docker:/sbin/nologin
/etc/group:root:x:0:
/etc/group:dockerroot:x:994:
/etc/group:docker:x:992:

grep搜索中指定或者排除某些文件

grep可以在搜索中指定(include)或者排除(exclude)某些文件。我們通過通配符來指定所include文件或者exclude文件

#目錄中遞歸搜索所有的.c 和.cpp文件
grep root . -r --include *.{c,cpp}

[root@host3 ~]# grep root /etc/ -r -l --include *.conf  # 此處的-l指僅列出文件名
/etc/systemd/logind.conf
/etc/dbus-1/system.d/org.freedesktop.hostname1.conf
/etc/dbus-1/system.d/org.freedesktop.import1.conf
/etc/dbus-1/system.d/org.freedesktop.locale1.conf
/etc/dbus-1/system.d/org.freedesktop.login1.conf
/etc/dbus-1/system.d/org.freedesktop.machine1.conf
/etc/dbus-1/system.d/org.freedesktop.systemd1.conf
/etc/dbus-1/system.d/org.freedesktop.timedate1.conf
/etc/dbus-1/system.d/wpa_supplicant.conf

#在搜索中排除所有的README文件
grep root . -r --exclude "README"
#******如果要排除目錄,用--exclude-dir,如果要從文件中讀取排除文件列表,使用--exclude-from FILE*****#

cut (略)


sed

#移除空白行
sed '/^$/d' file  # /pattern/d會移除匹配的樣式的行

#直接在文件中進行替換,使用指定的數字替換文件中所有的3位數的數字
[root@host3 ~]# cat sed.data 
11 abc 111 this 9 file contains 111 11 888 numbers 0000

[root@host3 ~]# sed -i 's/\b[0-9]\{3\}\b/NUMBER/g' sed.data 
[root@host3 ~]# cat sed.data 
11 abc NUMBER this 9 file contains NUMBER 11 NUMBER numbers 0000
#上面的命令替換了所有的3位數字。正則表達式\b[0-9]\{3\}\b用于匹配3位數字,[0-9]表示數位取值范圍,也就是從0-9
# {3}表示匹配之前的字符3次。其中的\用于轉義
# \b表示單詞邊界

sed -i .bak 's/abc/def/' file 
#此時sed不僅執行文件內容替換,還會創建一個名為file.bak的文件,其中包含著原始文件內容的副本

已匹配字符串標志&

在sed中,我們可以用&標記匹配樣式的字符串,這樣就能夠在替換字符串時使用已匹配的內容

[root@host3 ~]# echo this is my sister |sed 's/\w\+/<&>/g' #將所有的單詞替換成帶尖括號的單詞
<this> <is> <my> <sister>
[root@host3 ~]# echo this is my sister |sed 's/\w\+/[&]/g' #將所有的單詞替換成帶方括號的單詞
[this] [is] [my] [sister]

#正則表達式\w\+匹配每一個單詞,然后我們用[&]替換它,&對應于之前匹配到的單詞

引用

sed表達式通常用單引號來引用。不過也可以用雙引號,我們想在sed表達式中使用一些變量時,雙引號就派上了用場

[root@host3 ~]# text=hello
[root@host3 ~]# echo hello world |sed "s/$text/HELLO/"
HELLO world

awk

特殊變量:

  • NR:表示記錄數量,在執行過程中對應于當前行號
  • NF:表示字段數量,執行過程中對應于當前的字段數
  • $0:執行過程中當前行的文本內容

使用原則:

  • 確保整個awk命令用單引號括起來
  • 確保命令內所有引號成對出現
  • 確保用花括號括起來動作語句,用圓括號擴起條件語句
awk -F: '{print NR}' /etc/passwd #打印每一行的行號
awk -F: '{print NF}' /etc/passwd #打印每一行的列數

[root@host3 ~]# cat passwd 
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
elk:x:1000:1000::/home/elk:/bin/bash
ntp:x:38:38::/etc/ntp:/sbin/nologin
saslauth:x:998:76:Saslauthd user:/run/saslauthd:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
[root@host3 ~]# awk -F: '{print NR}' passwd 
1
2
3
4
5
6
7
8
[root@host3 ~]# awk -F: '{print NF}' passwd 
7
7
7
7
7
7
7
7
[root@host3 ~]# awk -F: 'END{print NF}' passwd 
7
[root@host3 ~]# awk -F: 'END{print NR}' passwd 
8
#只使用了end語句,每讀入一行,awk會將NR更新為對應的行號,當達到最后一行時NR就是最后一行的行號,于是就是文件的行數
  • awk 'BEGIN{ print "start" } pattern { commands } END{ print "end" }'
  • 可用單引號和雙引號將awk之后引起來
  • awk 'BEGIN{ statements } { statements } END{ statements }'
  • awk腳本通常有3部分組成,BEGIN,END,和帶模式匹配選項的常見語句塊。這3部分都是可選項
[root@host3 ~]# awk 'BEGIN{ i=0 } { i++ } END{ print i }' passwd 
8

awk拼接:

[root@mgmt-k8smaster01 deployment]# docker images|grep veh
192.168.1.74:5000/veh/zuul                           0.0.1-SNAPSHOT.34        41e9c323b825        26 hours ago        172MB
192.168.1.74:5000/veh/vehicleanalysis                0.0.1-SNAPSHOT.38        bca9981ac781        26 hours ago        210MB
192.168.1.74:5000/veh/masterveh                      0.0.1-SNAPSHOT.88        265e448020f3        26 hours ago        209MB
192.168.1.74:5000/veh/obugateway                     0.0.1-SNAPSHOT.18        a4b3309beccd        8 days ago          182MB
192.168.1.74:5000/veh/frontend                       1.0.33                   357b20afec08        11 days ago         131MB
192.168.1.74:5000/veh/rtkconsumer                    0.0.1-SNAPSHOT.12        4c2e63b5b2f6        2 weeks ago         200MB
192.168.1.74:5000/veh/user                           0.0.1-SNAPSHOT.14        015fc6516533        2 weeks ago         186MB
192.168.1.74:5000/veh/rtkgw                          0.0.1-SNAPSHOT.12        a17a3eed4d28        2 months ago        173MB
192.168.1.74:5000/veh/websocket                      0.0.1-SNAPSHOT.7         a1af778846e6        2 months ago        179MB
192.168.1.74:5000/veh/vehconsumer                    0.0.1-SNAPSHOT.20        4a763860a5c5        2 months ago        200MB
192.168.1.74:5000/veh/dfconsumer                     0.0.1-SNAPSHOT.41        2e3471d6ca27        2 months ago        200MB
192.168.1.74:5000/veh/auth                           0.0.1-SNAPSHOT.4         be5c86dd285b        3 months ago        185MB
[root@mgmt-k8smaster01 deployment]# docker images |grep veh |awk '{a=$1;b=$2;c=(a":"b);print c}'
192.168.1.74:5000/veh/zuul:0.0.1-SNAPSHOT.34
192.168.1.74:5000/veh/vehicleanalysis:0.0.1-SNAPSHOT.38
192.168.1.74:5000/veh/masterveh:0.0.1-SNAPSHOT.88
192.168.1.74:5000/veh/obugateway:0.0.1-SNAPSHOT.18
192.168.1.74:5000/veh/frontend:1.0.33
192.168.1.74:5000/veh/rtkconsumer:0.0.1-SNAPSHOT.12
192.168.1.74:5000/veh/user:0.0.1-SNAPSHOT.14
192.168.1.74:5000/veh/rtkgw:0.0.1-SNAPSHOT.12
192.168.1.74:5000/veh/websocket:0.0.1-SNAPSHOT.7
192.168.1.74:5000/veh/vehconsumer:0.0.1-SNAPSHOT.20
192.168.1.74:5000/veh/dfconsumer:0.0.1-SNAPSHOT.41
192.168.1.74:5000/veh/auth:0.0.1-SNAPSHOT.4

awk工作方式如下:

  • 1.執行BEGIN { commands } 語句塊中內容
  • 2.執行中間塊 pattern { commands }。重復這個過程指導文件全部讀取完畢
  • 3.當讀至輸入流末尾時,執行END{ commands }語句塊

我們可以將每一行中的第一個字段的值進行累加,即列求和

[root@host3 ~]# cat sum.data 
1 2 3 4 5 6
2 2 2 2 2 2
3 3 3 3 3 3
5 5 5 6 6 6
[root@host3 ~]# cat sum.data |awk 'BEGIN{ sum=0 }  { print $1; sum+=$1 } END { print sum }'
1
2
3
5
11

[root@host3 ~]# awk '{if($2==3)print $0}' sum.data 
3 3 3 3 3 3
[root@host3 ~]# awk '{if($2==5)print $0}' sum.data 
5 5 5 6 6 6

#每個值加1
[root@host2 ~]# cat passwd 
1:2:3:4
5:5:5:5
3:2:3:5
[root@host2 ~]# cat passwd |awk -F: '{for(i=1;i<=NF;i++){$i+=1}}{print $0}'
2 3 4 5
6 6 6 6
4 3 4 6

[root@host2 ~]# cat passwd |awk -F: '{$2=$2+1;print $0}' 
1 3 3 4
5 6 5 5
3 3 3 5
[root@host2 ~]# cat passwd |awk -F: '{if($2==2) $2=$2+1;print $0}'
1 3 3 4
5:5:5:5
3 3 3 5

#將所有2替換成jack fuck,需要更規范的話表達式也要用圓括號括起來
[root@host2 ~]#  cat passwd |awk -F: '{if($2==2) $2="jack fuck";print $0}'       
1 jack fuck 3 4
5:5:5:5
3 jack fuck 3 5
[root@host2 ~]#  cat passwd |awk -F: '{if($2==2) ($2="jack fuck");print $0}'
1 jack fuck 3 4
5:5:5:5
3 jack fuck 3 5

將外部變量傳遞給awk

#我們借助選項-v可以將外部值傳遞給awk
[root@host3 ~]# VAR1=10000
[root@host3 ~]# echo |awk -v VAR=$VAR1 '{print VAR}'
10000
#輸入來自標準輸出,所以有echo

#還有另外一種靈活的方法可以將多個外部變量傳遞給awk
[root@host3 ~]# VAR1=10000
[root@host3 ~]# VAR2=20000
[root@host3 ~]# echo |awk '{ print v1,v2 }' v1=$VAR1 v2=$VAR2
10000 20000

使用過濾模式對awk處理的行進行過濾

[root@host3 ~]# cat sum.data 
1 2 3 4 5 6
2 2 2 2 2 2
3 3 3 3 3 3
5 5 5 6 6 6

#行號小于3的行
[root@host3 ~]# awk 'NR<3' sum.data 
1 2 3 4 5 6
2 2 2 2 2 2

#行號為1到4之間的行
[root@host3 ~]# awk 'NR==1,NR==3' sum.data 
1 2 3 4 5 6
2 2 2 2 2 2
3 3 3 3 3 3

#包含樣式linux的行
awk '/linux/'

#不包含樣式linux的行
awk '!/linux/'

按列合并多個文件

paste


wget

  • 下載多個文件 wget URL1 URL2 URL3
  • wget用-t指定次數,可以不停重試 wget -t 0 URL
  • 可以限速: wget --limit-rate 20k http://www.baidu.com
  • 下載多個文件時可以配額,配額一旦用盡就會停止下載 wget --quota 100M URL1 URL2 URL3
  • 斷點續傳 wget -c URL
  • 訪問需要認證的http或者ftp頁面 wget --user username --password pass URL,也可以不在命令行中指定密碼,而由網頁提示并手動輸入密碼,這就需要將--password改成--ask-password

復制整個網站(爬蟲)

wget有一個選項可以使其像爬蟲一樣以遞歸的方式遍歷網頁上所有的URL鏈接,并逐個下載。這樣一來我們可以得到這個網站的所有頁面

wget --mirror --convert-links www.chinanews.com
[root@host3 tmp]# ls
www.chinanews.com
[root@host3 tmp]# cd www.chinanews.com/
[root@host3 www.chinanews.com]# ls
allspecial  auto   cj             common   gangao  hb  huaren      js          m     piaowu  robots.txt   sh      society  taiwan  tp
app         china  cns2012.shtml  fileftp  gn      hr  index.html  live.shtml  part  pv      scroll-news  shipin  stock    theory
[root@host3 www.chinanews.com]# ll
 260
drwxr-xr-x 2 root root     25 10?? 12 14:11 allspecial
drwxr-xr-x 3 root root     23 10?? 12 14:11 app
drwxr-xr-x 3 root root     18 10?? 12 14:11 auto
drwxr-xr-x 2 root root     24 10?? 12 14:11 china
drwxr-xr-x 3 root root     18 10?? 12 14:11 cj
-rw-r--r-- 1 root root  15799 10?? 12 14:11 cns2012.shtml
drwxr-xr-x 3 root root     46 10?? 12 14:11 common
drwxr-xr-x 6 root root     54 10?? 12 14:11 fileftp
drwxr-xr-x 2 root root     24 10?? 12 14:11 gangao
drwxr-xr-x 4 root root     27 10?? 12 14:11 gn
drwxr-xr-x 2 root root     24 10?? 12 14:11 hb
drwxr-xr-x 3 root root     18 10?? 12 14:11 hr
drwxr-xr-x 2 root root     24 10?? 12 14:11 huaren
-rw-r--r-- 1 root root 184362 10?? 12 14:11 index.html
drwxr-xr-x 2 root root     26 10?? 12 14:11 js

#-convert-links指示wget將頁面的鏈接地址轉換為本地地址

以純文本形式下載網頁

網頁下下來默認是html格式需要瀏覽器去查看,lynx是一個頗有玩頭的基于命令行的瀏覽器,可以利用他獲取純文本形式的網頁

#用lynx 命令-dump選項將網頁的內容以ascii編碼的形式存儲到文本文件中
[root@host3 tmp]# yum -y install lynx
[root@host3 tmp]# lynx www.chinanews.com -dump > abc.txt
[root@host3 tmp]# cat abc.txt
 ...
 1.   http://www.chinanews.com/kong/2019/10-12/8976714.shtml
 2.   http://www.chinanews.com/kong/2019/10-12/8976812.shtml
 3.   http://www.chinanews.com/kong/2019/10-12/8976721.shtml
 4.   http://www.chinanews.com/kong/2019/10-12/8976690.shtml
 5.   http://www.chinanews.com/kong/2019/10-12/8976817.shtml
 6.   http://www.chinanews.com/kong/2019/10-12/8976794.shtml
 7.   http://www.chinanews.com/kong/2019/10-12/8976853.shtml
 8.   http://www.chinanews.com/kong/2019/10-12/8976803.shtml
 9.   http://www.chinanews.com/sh/2019/10-12/8976754.shtml
 10.  http://www.chinanews.com/tp/chart/index.shtml
 11.  http://www.chinanews.com/tp/hd2011/2019/10-12/907641.shtml
 12.  http://www.chinanews.com/tp/hd2011/2019/10-12/907637.shtml
 13.  http://www.chinanews.com/tp/hd2011/2019/10-12/907651.shtml
 14.  http://www.chinanews.com/tp/hd2011/2019/10-12/907644.shtml
 15.  http://www.chinanews.com/tp/hd2011/2019/10-12/907675.shtml
 16.  http://www.chinanews.com/tp/hd2011/2019/10-12/907683.shtml
 17.  http://www.chinanews.com/tp/hd2011/2019/10-12/907656.shtml
 18.  http://www.ecns.cn/video/2019-10-12/detail-ifzpuyxh6816910.shtml
 19.  http://www.ecns.cn/video/2019-10-11/detail-ifzpuyxh6815962.shtml
 20.  http://www.ecns.cn/video/2019-10-11/detail-ifzpuyxh6815122.shtml
 21.  http://www.ecns.cn/video/2019-10-11/detail-ifzpuyxh6815100.shtml

curl

設置cookie

要指定cookie,使用--cookie "COOKIES"選項

cookies需要以name=value的形式來給出。多個cookie之間使用分號分隔。例如:--cookie "user=slynux;pass=hack"

如果要將cookie另存為一個文件,使用--cookie-jar選項。例如 --cookie-jar cookie_file

設置用戶代理字符串

如果不指定用戶代理(user agent),一些需要檢驗用戶代理的網頁就無法顯示。你肯定碰到過一些成就的網站只能ie下工作。如果使用其他瀏覽器,這些網站就會提示說她只能IE訪問。這是因為這些網站檢查了用戶代理。你可以用curl來設置用戶代理

  • --user-agent或-A選項用于設置用戶代理: curl URL --user-agent "Mozilla/5.0"
  • -H頭部信息傳遞多個頭部信息: curl -H "Host: www.baidu.com" -H "Accept-language: en" URL

只打印文件頭

-I或者--head

[root@host3 tmp]# curl -I www.chinanews.com
HTTP/1.1 200 OK
Date: Sat, 12 Oct 2019 08:47:31 GMT
Content-Type: text/html
Connection: keep-alive
Expires: Sat, 12 Oct 2019 08:48:22 GMT
Server: nginx/1.12.2
Cache-Control: max-age=120
Age: 69
X-Via: 1.1 PSbjwjBGP2ih237:5 (Cdn Cache Server V2.0), 1.1 shx92:3 (Cdn Cache Server V2.0), 1.1 PSjsczsxrq176:3 (Cdn Cache Server V2.0), 1.1 iyidong70:11 (Cdn Cache Server V2.0)

解析網站數據

lynx是一個基于命令行的網頁瀏覽器。它并不會輸出一堆原始的html代碼,二是能夠顯示網站的文本版本,這個文本版和我們在瀏覽器中看到的頁面一模一樣。這樣一來,就免去了移除html標簽的工作。這里用到lynx的-nolist選項,這是因為不需要給每個鏈接自動加上數字標號。

[root@host3 tmp]# lynx  www.chinanews.com -dump -nolist 
 ...
 友情鏈接
   外交部|國僑辦|中紀委監察部|國臺辦|中國法院網|人民網|新華網|中國網|央視網|國際在線|中國青年網|中國經濟網|中國臺灣網|央廣網|
   中國西藏網|中青在線|光明網|中國軍網|法制網|中華網|新京報|京報網|京華網|四川廣播電視臺|千龍網|華龍網|紅 網|舜 網|膠東在線|
   東北新聞網|東北網|齊魯熱線|四川新聞網|長城網|南方網|北方網|東方網|新浪|搜狐|網易|騰訊|華夏經緯|東方財富網|金融界|慧科|房天下

   關于我們| About us| 聯系我們| 廣告服務| 供稿服務| 法律聲明| 招聘信息| 網站地圖
   | 留言反饋

   本網站所刊載信息,不代表中新社和中新網觀點。 刊用本網站稿件,務經書面授權。

   未經授權禁止轉載、摘編、復制及建立鏡像,違者將依法追究法律責任。

   [網上傳播視聽節目許可證(0106168)] [京ICP證040655號] [ [ghs.png] 京公網安備
   11000002003042號] [京ICP備05004340號-1] 總機:86-10-87826688
   違法和不良信息舉報電話:15699788000 舉報郵箱:jubao@chinanews.com.cn 舉報受理和處置管理辦法

   Copyright ?1999- 2019 chinanews.com. All Rights Reserved

                             [_1077593327_3.gif]

                  [U194P4T47D45262F978DT20190920162854.jpg]

                             [_1077593327_3.gif]

                  [U194P4T47D45262F979DT20190920162854.jpg]

case

case $變量名 in
"值 1")
;;
如果變量的值等于值1,則執行程序1,值
2")
如果變量的值等于值2,則執行程序2
…省略其他分支…
*)
如果變量的值都不是以上的值,則執行此程序
;;
esac

#!/bin/bash
#判斷用戶輸入
read -p "Please choose yes/no: " -t 30 cho
#在屏幕上輸出"請選擇yes/no",然后把用戶選擇賦予變量cho
case $cho in
#判斷變量cho的值
    "yes")
    #如果是yes
        echo "Your choose is yes!"
        #則執行程序1
        ;;
    "no")
    #如果是no
        echo "Your choose is no!"
        #則執行程序2
        ;;
    *)
    #如果既不是yes,也不是no
    echo "Your choose is error!"
    #則執行此程序
    ;;
esac

查找網站中的無效鏈接

一個人采用人工方式來檢查網站上的每一個頁面,以便找出無效鏈接。要識別鏈接并從中找出無效鏈接


[root@host3 tmp]# cat find_broken.sh 
#!/bin/bash
if [ $# -ne 1 ];
then
  echo -e "$Usage: $0 URL\n"
  exit 1;
fi

echo Broken links:

# $$為腳本運行時的pid
mkdir /tmp/$$.lynx
cd /tmp/$$.lynx

lynx -traversal $1 > /dev/null
count=0;

sort -u reject.data > links.txt

while read link;
do
  output=`curl -I $link -s | grep "HTTP/.*OK"`
  if [[ -z $output ]];
    then $link;
    let count++
  fi
done < links.txt

[ $count -eq 0 ] && echo No broken links found.

#lynx -traversal URL會在工作目錄下生成數個文件,其中包括reject.dat,該文件包含網站中的所有鏈接。sort -u用來建立一個不包含重復項的列表。我們curl檢驗頭部即可

#sort -u去重,類似于uniq
  • lynx -traversal從名稱上來看,jeject.dat中應該包含的無效URL的列表,實際并非如此,而是將所有的URL全都放在了這個文件中
  • lynx還生成了一個traverse.error的文件,其中包含了所有在瀏覽過程中存在問題的URL。但是lynx只會將返回HTTP404的URL,會遺漏那些存其他類型錯誤的URL,這是為何要手動檢查返回狀態的原因
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

龙口市| 个旧市| 会宁县| 清流县| 绩溪县| 东港市| 琼结县| 衡南县| 赤峰市| 自贡市| 天镇县| 水城县| 巴林右旗| 额尔古纳市| 蓬溪县| 海晏县| 樟树市| 越西县| 唐海县| 利津县| 浏阳市| 吉隆县| 泾川县| 静宁县| 新津县| 台前县| 景德镇市| 泰顺县| 锡林郭勒盟| 平陆县| 蓝田县| 吉水县| 灵武市| 正阳县| 九龙城区| 眉山市| 溧阳市| 罗田县| 淳化县| 乌拉特前旗| 屯昌县|