1. 程式人生 > >linux shell指令碼攻略 學習筆記3 -- 第三章 以檔案之名

linux shell指令碼攻略 學習筆記3 -- 第三章 以檔案之名

第三章主要跟檔案的處理相關,小結各節內容如下:

1,簡介

概念:Unix將系統中的一切都視為檔案;如普通檔案、目錄、終端、符號連結、命名管道等等,都是一種檔案;

2, 生成測試用的檔案

1)某些時候,需要製作一些測試用的檔案,我們不用單獨寫程式去生成,可以直接採用現有的dd命令;

由於上一章已有介紹,此處僅舉例如下:

$ dd if=/dev/zero of=test.data bs=1M count=2     #生成一個1M*2=2M的內容全為0的檔案test.data

2)另,可以使用dd命令傳輸大量資料,來測試當前記憶體的操作速度,如使用1)中命令語句後,會有以下類似列印:

2+0 recordsin

2+0 recordsout

2097152 bytes (2.1 MB) copied, 0.00660423s, 318 MB/s

3,文字檔案的交集和差集

1)理解交集和差集,以及求差

舉個例子:A {1, 2,3}, B {3, 4, 5}

交集,兩個檔案共有的行,例中為 {3}

求差,兩個檔案所不同的那些行,例中為 {1, 2, 4, 5}

差集,僅在A檔案中的行或僅在B檔案中的行,例中為A差集{1, 2},B差集{4, 5}

2)使用命令comm, compare two sorted files line by line

格式 comm file1file2

注,file1、file2應該為排序後的檔案(有重複行也可以)

例:

$ cat afile

a

b

b

c

d

$ cat bfile

a

d

f

$ comm afile bfile

                a

b

b

c

                d

       f

解釋,comm的結果,第一列為afile僅有的行,第二列為bfile僅有的行,第三列為afile bfile都有的行;各列以\t分割;

3)可用選項,得到交集、求差、差集

-1,comm結果中刪除第1列;

-2,comm結果中刪除第2列;

-3,comm結果中刪除第3列;

則,獲取交集的語句:commafile bfile -1 -2

獲取求差的語句:commafile bfile -3 | sed ‘s/\t//’

獲取A的差集:comm afile bfile -2 -3(B的差集相似)

注,上面例子有有sed的使用,有個知識點記錄下:

區別下面兩語句,

sed 's///'          只替換第一個匹配字元

sed 's///g'         替換所有匹配字元

例:

$ echo "aaaabbbbbcccccccaaaaa" |sed 's/a/A/g'

AAAAbbbbbcccccccAAAAA

$ echo "aaaabbbbbcccccccaaaaa" |sed 's/a/A/'

Aaaabbbbbcccccccaaaaa

4,查詢並刪除重複檔案

這個小節寫了一個指令碼,利用了md5sum、comm、awk、xargs、rm、ls等各shell工具,來完成刪除重複檔案的任務;

程式碼似乎有問題,使用不通過,還沒弄清楚,暫不做記錄...

5,建立路徑目錄 mkdir

基本使用:mkdir dirpath

使用引數:mkdir –p dirpath,使用-p,可以忽略所有已存在目錄,並建立缺少的部分;

例子:

$ mkdir testdir

mkdir: cannot create directory `testdir':File exists

$ mkdir testdir/adir

$ tree testdir/

testdir/

`-- adir

$ mkdir -p testdir/adir/bdir/cdir

$ tree testdir/

testdir/

`-- adir

   `-- bdir

       `-- cdir

6,檔案的許可權、所有權、setuid、setgid、粘滯位

ls –l,看出檔案屬性,如下:

-rw-r--r-- 2 philip philip 29 Jul  5 22:56 hardafile

lrwxrwxrwx 1 philip philip 10 Jul  5 22:57 symbolafile -> afile

1)許可權、所有權

許可權為rwxrwxrwx這9位內容,三位分割分別對應使用者、組、其它的讀、寫、執行許可權;

所有權為philip philip,分別對應擁有使用者和擁有組;

2)setuid、setgid

setuid,設定使用者ID位;setgid,設定使用者組ID位:個人理解,當前使用者對該檔案具有 檔案擁有者所具有的許可權;setuid出現在使用者的可執行位上,如rwS------,setgid出現在組的可執行位上,如---rwS---

3)粘滯位

目錄才有該屬性,放在可執行位上,表示對該目錄具有寫許可權的使用者在滿足以下條件時才能刪除目錄中的檔案:擁有此檔案、或擁有此目錄、或為root;

可執行且無粘滯位       --x

可執行且粘滯位           --T

不可執行且粘滯位       --t

注,粘滯位以前還有別的意思,可見apue p83

4)相關設定命令 chmod chown

看例子:

chmod u=rwxg=rw o=r filename,u 使用者,g 組,o 其它

chmod u+x filename

chmod a+r filename,a表示all

chmod o-w filename

chmod 764 filename,使用者為7,對應rwx(111);組為6,對應rw-(110);其它為4,對應r--(100);

chmod +s filename,設定setuid、setgid;

chmod a+t filename,設定粘滯位;

chmod 777 –R.     ;-R,遞迴方式

chown root /u

change the owner of /u to "root".

chown root:staff /u

likewise, but also change its group to "staff".

chown -hR root /u

change the owner of /u and subfiles to "root".

chown user.group –R    ;-R,遞迴方式

7,建立不可刪除檔案

在ext2、ext3、ext4等檔案系統中,可建立不可修改(immutable)檔案,命令用chattr;

chattr - change file attributes on a Linuxfile system

chattr +i filename,變為不可刪除;i,immutable;

chattr –i filename,變回可刪除;

8,生成(空白)檔案

touch命令,生成空白檔案,但如果檔案存在,則touch用來修改檔案的時間戳;

格式:touch filename,建立新檔案或更新時間戳到現在;

touch –a filename,只更新access time;

touch –m filename,只更新modif time;

touch –d “Jan 20 2010”filename,更新到-d所指示的時間;

9,符號連線,ln

ln命令

-s, --symbolic        make symbolic links instead of hard links,而直接ln target symbol則為硬連線

-L,logical            make hardlinks to symbolic link references,對符號連線所指向的檔案進行硬連線

a,harda,symbola,harda為a的硬連結檔案,symbola為b的符號連結檔案;理解硬連結和符號連線:

1)a和harda指向同一內容(inodes),但連線點數量加1;symbola是一個新檔案;

2)刪除a,harda沒事,symbola 將打不開了

找符號連結檔案的方法:

1) ls –l | grep “^l”

2) find . –type l

另:讀一個符號連結所指向的原始檔,命令readlink(print value of a symbolic link or canonical file name),如

$ readlink web

/var/www

10,列舉檔案型別統計資訊

本小節是一個運用示例,統計某目錄下檔案型別的資訊;

1)區別檔案型別的幾個工具,find –type, ls –l, file,具體示例如下:

find :

$ declare –A count

$ count[“file”]=`find . –type f | wc | awk ‘{print$1}’        #注意,可以用關聯陣列進行統計

ls :

$ ls –l dir | grep “^d” | wc -l

file :

file filename

file –b filename      #-b, brief

2)寫指令碼程式時,遇到return和exit的使用:

指令碼任意處可以用exit退出指令碼程式;

return,can only `return' from a function or sourced script,即return用在function和sourced script,對於sourced script的理解:進行了實驗,在指令碼中function外加return語句,則如果由./script執行,則會出現上面的錯誤提示,需改為source script進行執行則正常;具體原理還不清楚;

3)for file in $all_files         #all_files是想包含所有檔名,形如”aa bb cc dd”;但如果某檔案的名字中有

       …                                    #空格,如上面例子中有一個檔案就叫”cc dd”,這樣for會將cc、dd拆分,

                                               #以為有兩個檔案,導致處理出錯

一種改進的方式:

       while read line                     #filename為一個檔名,檔案內的內容在本小節例子中為所有檔案的名字,以

       do                                          #換行符分割;如下

              something                     #     aa

       done< filename                   #     bb…

       while read line                     #上面是以檔案內容作為stdin,然後給read去讀

       do                                          #這裡只是用子程序的輸入作為stdin,注意子程序前面有一個”<”

              something

       done< <(find .)

4)注意,指令碼中變數名最好加上””,以避免有空格的變數字串!

11,環迴文件與掛載

12,生成ISO檔案與混合ISO

上面兩小節先不做小結,個人覺得使用的機會會小點

13,查詢檔案差異及進行修補 diff與patch命令

13.1 查詢差異 diff命令

基本使用:

$ diff afile bfile

2c2

< 345

---

> 346

一體化形式的diff(結果可讀性更好):

$ diff -u afile bfile

--- afile   2015-07-0818:17:07.082191414 -0700

+++ bfile 2015-07-0817:46:16.986140468 -0700

@@ -1,3 +1,3 @@

 123

-345

+346

 asd

13.2 修補,即打patch,patch命令

首先由diff生成patch檔案,可以diff afile bfile > ab.patch或diff –u afile bfile > ab.patch;

然後patch –p1afile < ab.patch,將patch打到afile上,此後afile與源bfile一樣;

       patch–p1 bfile < ab.patch,將patch打到bfile上,此後bfile與源afile一樣;

會有列印:“patchingfile afile”

注:-pnum引數的含義,Strip the smallest prefix containing num leading slashes from each file  name found  in the  patch  file.將patch中的檔名字,刪去前num個斜槓及斜槓前面的內容;具體含義man或網上查資料吧;

13.3 恢復,使用與修補同樣的命令,即

patch –p1 afile < ab.patch,對bfie同理;

會有列印:

patching file afile

Reversed (or previously applied) patchdetected!  Assume -R? [n]

如果使用patch –R –p1 afile < ab.patch則不會出現-R提示;

13.4 針對目錄生成diff資訊

會對目錄中所有的內容生成差異輸出,常用命令如:

$diff –Naur dir1 dir2

-N:將缺失的檔案視為空檔案;

-a:將所有檔案視為文字檔案;

-u:生成一體化輸出;

-r:遍歷目錄下所有檔案;

14,列印,head與tail命令

14.1 基本用法,都是例子:

head file                                        #列印前10行

head –n 4 file                              #列印前4行

head –n –4 file                            #列印除了最後4行的所有行(理解,最後一行為第0行,第一行為第-len行,

                                                       # 則此時列印第-len ~ -4行)

tail                                                  #列印最後10行

tail –n 5 file                                  #列印最後5行

tail –n +(N+1) file                        #列印除了前面N行的所有行(理解,從第N+1行開始)

head總是列印從頭開始的內容;tail總是列印某行到末尾的內容;結合head與tai可列印固定的某些行,如: seq 1 100 | head –n 50| tail –n 20 將輸出31~50;

14.2 tail的特殊用法

tail –f growing_file

-f引數,它使tail密切關注檔案中新新增的內容;

如tail –f afile;另一邊echo “Asdasd” >> afile,則tail的那個終端會相應的更新輸出;預設1秒更新一次;

tail –f filename –s n,每n秒更新;

tail –f filename –pid PID,程序PID結束時,tail也接收跟蹤filename;

--pid=PID

      with -f, terminate after process ID, PIDdies

另,涉及到一個命令pidof processname,pidof -- findthe process ID of a running program.

15,只列出目錄的方法

本小節也是實踐的例子,有以下幾種只打印目錄的方法:

1)ls –d */

接收,ls */,打印出匹配”*/”的檔案,那將會是目錄(因為以‘/’結尾);但ls dir將會打印出目錄下的檔案內容,而不是該目錄名,所以此時加上-d引數,就將只打印該目錄名而非目錄下的內容;

例:dir1下有檔案afile bfile,則,

$ ls dir1

afile  bfile

$ ls -d dir1

dir1

2)ls –F | grep “/$“

ls –F引數,會在輸出項後面加上一個代表檔案型別的字元,如* / @ 等,對應檔案是*,對應目錄是/ ;所以只要過來以/結尾的內容即可;

3)ls –l | grep “^d”

ls –l,打印出檔案的詳細資訊,最前面將會代表檔案類似的字元,在本章第6小節也說明了,這裡不在詳述;

4)find . –type d –maxdepth 1

這個在find命令的介紹中有(第2章第4節),也不在詳述了;

注:不能用dir命令實現,dir -- list directory contents,即其功能是列出目錄中內容,而不是目錄;

16,pushd popd命令

以上兩命令用在多個目錄間進行切換,此時可以不再使用“cd + 相應路徑名”的命令了;看例子來理解:

原本在目錄/disk/test下,

1)pushd /disk/test/dir1

此時將/disk/test/dir1壓入棧,此時棧內將有/disk/test/dir1 /disk/test兩個目錄成員;

繼續壓入幾個目錄後,我們檢視目錄棧內的內容,

2)dirs(注意區別上小節提到的dir與dirs)

$ dirs      #此時打印出棧內內容,我們給棧的內容將序號,如下

/disk/test/dir2/ddd   /disk/test/dir1/ddd   /disk/test/dir1       /disk/test

0                1                 2                 3

-3               -2                 -1                -0

現在我們在/disk/test/dir2/ddd目錄下,要跳到/disk/test/dir1下,只需要執行:

3)$ pushd +2

/disk/test/dir1 /disk/test/disk/test/dir2/ddd /disk/test/dir1/ddd

$ pwd

/disk/test/dir1

即執行pushd +2,此時已切換到前面的2號目錄下了;注意此時目錄棧的內容也跟著旋轉了!

另外,也可以執行pushd –n來切換目錄,參考上面的負數序號;

4)從棧中刪除路徑

$ popd

這將會刪除棧頂的路徑,並切換到下一個目錄

$ popd +no,則從列表中刪除第no號目錄,此序號的用法同上pushd+no(-no類似)

注意:實驗發現,在用pushdpopd時,用cd去切換路徑,會把棧頂的內容給替換掉,如下:

$ dirs

/disk/test /disk/test/dir2/ddd /disk/test/dir1/ddd/disk/test/dir1

$ pwd

/disk/test

$ cd dir1/ddd/

$ pwd

/disk/test/dir1/ddd

$ dirs

/disk/test/dir1/ddd /disk/test/dir2/ddd /disk/test/dir1/ddd/disk/test/dir1

5)還有一個,在兩個目錄下相互切換,大家都知道的“cd –”

17,統計檔案行數、單詞數、字元數

(如常用來統計程式碼行數LOC,line of code …)

wc 命令,word count

基本使用:

wc file,打印出file中的行數、單詞數、字元數,如

$ wc tmp

1     1     14    tmp

wc –l file,僅打印出行數;

wc –w file,僅打印出單詞數;

wc –c file,僅打印出字元數;

wc –L file,打印出file中最長行的長度;

17,列印目錄樹

tree命令,有時需要自己安裝該工具;

1)直接使用tree命令即可:

$ tree

.

├── afile

├── bfile

└── ddd

    └── tmp

2)一些有用的引數:

tree path –P PATTERN #用萬用字元限定只打印相應的檔案,如tree path –P “*.cpp”

tree path –I PATTERN #與-P相反,取某些樣式之外的那些檔案;

tree –h,同時列印檔案和目錄的大小;

tree path –H http://localhost –o out.html,可以生成一個html檔案,該html檔案展現了目錄樹的內容;