首頁>技術>

目錄

1. 關於路徑和萬用字元

2. 檢視目錄內容(ls和tree)

2.1 ls命令

2.2 tree命令

3. 檔案的時間戳(atime/ctime/mtime)

3.1 關於relatime

4.1 建立目錄mkdir

4.2 建立檔案touch

5. 檢視檔案型別file命令

6. 檔案/目錄複製和移動

6.1 cp命令

6.2 scp命令和執行過程分析

6.3 mv命令

6.4 mv的一個經典問題(mv的本質)

7. 檢視檔案內容

7.1 cat命令

7.2 tac

7.3 head

7.4 tail

7.5 nl

7.6 more和less

7.7 比較檔案內容

8. 檔案查詢類命令

8.1 which

8.2 whereis

8.3 whatis

8.4 locate

8.5 find

1. 關於路徑和萬用字元

Linux中分絕對路徑和相對路徑,絕對路徑一定是從/開始寫的,相對路徑不從根開始寫,還可能使用路徑符號。

路徑展開符號:

.  :(一個點)表示當前目錄.. :(兩個點)表示上一層目錄-  :(一個短橫線)表示上一次使用的目錄,例如從/tmp直接切換到/etc下,"-"就表示/tmp~  :(波浪符號)表示使用者的家目錄,例如"~account"表示account使用者的家目錄/dir/和/dir:一般都表示dir目錄和dir目錄中的檔案。但在有些地方會嚴格區分是否加尾              隨斜線,此時對於加了尾隨斜線的表示此目錄中的檔案,不加尾隨斜線的表示              該目錄本身和此目錄中的檔案

切換路徑用cd命令;

顯示當前所在目錄用pwd命令。若當前所在目錄為連結目錄,使用pwd顯示的將是連結自身,使用-P選項將定位到連結的原始目錄。

[root@ansible6_node1 ~]# ll ; cd tmp; pwd; pwd -Ptotal 0lrwxrwxrwx 1 root root 4 May 30 19:17 tmp -> /tmp/root/tmp/tmp

獲取檔名使用basename命令,獲取檔案所在目錄使用dirname命令。注意,這兩個命令其實不太完善,它不會檢查檔案或目錄是否存在,只要寫出來了就會去獲取。

[root@xuexi tmp]# basename /etc/shadowshadow[root@xuexi tmp]# basename /etc/etc[root@xuexi tmp]# dirname /etc/shadow/etc[root@xuexi tmp]# dirname /etc/    # 對目錄使用dirname獲取的是上級目錄/[root@server1 ~]# dirname /kalsldk/kdkskks/djfjdjdjsj   # 獲取不存在的目錄/kalsldk/kdkskks

bash shell萬用字元:

可以使用"*"、"?"、"[]"等的萬用字元來擴充套件路徑或檔名。例如, ls *.log 將列出當前路徑下所有以".log"字元結尾的檔名(但不包括"."開頭的隱藏檔案)。

預設情況下,bash提供的萬用字元規則比較弱,例如"*"無法匹配檔名開頭的".",無法匹配路徑分隔符號(即斜線"/"),但可以透過set或shopt命令開啟額外的通配功能,實現更完善的萬用字元規則。

例如,預設情況下,想要匹配目錄/path下所有隱藏檔案和非隱藏檔案,如下:

ls  .*  *

開啟dotglob功能,"*"就可以匹配以"."開頭的檔案:

shopt -s dotglobls *

有時想要遞迴到目錄內部,又想要匹配檔名,例如想要遞迴找出多層目錄/path下所有的".css"檔案,這時可以開啟globstar功能,使用"兩星連珠"(**)就可以匹配匹配路徑斜線。

shopt -s globstar       # 開啟星號匹配模式ls /path/**/*.css       # 開啟後,使用兩個星號**就會匹配斜線

必須要說明的是,對於非bash內建命令,有些可能也提供了自己的萬用字元匹配方式,它們的通配模式和shell提供的可能並不一樣。例如find的"-name"選項就可以採用自己的萬用字元,它的星號"*"可以匹配以點開頭的隱藏檔案,如 find /var/log -name "*.log" 。

2. 檢視目錄內容(ls和tree)

ls命令列出目錄中的內容,和dir命令完全等價。tree命令按樹狀結構遞迴列出目錄和子目錄中的內容,而ls使用-R選項時才會遞迴列出。

注意:ls的結果中是以製表符分隔多個檔案的。

2.1 ls命令

ls的各個選項說明如下:

-l:(long)長格式顯示,即顯示屬性等資訊(包括mtime)。注意:顯示的目錄大小是節點所佔大小。像win一樣計算目錄大小時包括檔案大小要用du -sh

-c:列出ctime

-u:列出atime

-d:(direcorty)檢視目錄本身屬性資訊,不檢視目錄裡面的東西。不加-d會檢視裡面檔案的資訊

-a:會顯示所有檔案,包括兩個相對路徑的檔案"."和".."以及以點開頭的隱藏檔案

-A:會列出絕大多數檔案,即忽略兩個相對路徑的檔案"."和".."

-h:(human)人類可讀的格式,將位元組換成k,將K換成M,將M換成G

-i:(inode)許可權屬性的前面加上一堆數字

-p:對目錄加上/識別符號以作區分

-F:對不同型別的檔案加上不同識別符號以作區分,對目錄加的檔案也是/

-t:按修改時間排序內容。不加任何改變順序的選項時,ls預設按照字母順序排序

-r:反轉排序

-R:遞迴顯示

-S:按檔案大小排序,預設降序排序

--color:顯示顏色

-m:使用逗號分隔各檔案,當然,只適用於未使用長格式(ls -l)的情況

-1:(數值一),以換行符分隔檔案,當然,和-m或-l(小寫字母)是衝突的

-I pattern:忽略被pattern匹配到的檔案

注意,ls以-h顯示檔案大小時,一般顯示的都是不帶B的單位,如K/M/G,它們的轉換比例是1024,如果顯示的都是帶了B的,如KB/MB/GB,則它們的轉換比例為1000而非1024,一般很少顯示帶B的大小。

不得不說,ls本身不能顯示出檔案的全路徑名是一大缺陷,不過好在使用find命令可以很簡單的就獲取到。

以下是使用ls -l顯示檔案長格式的屬性。

[root@xuexi ~]# ll /tmpdrwxr-xr-x  2 root root 4096 Mar 26 16:44 test1

可以查出7列屬性。

2.2 tree命令

有可能tree命令不存在,需要安裝tree包才有(安裝:yum -y install tree)。

tree命令的選項說明如下:

【 匹配選項:】

-L:用於指定遞迴顯示的深度,指定的深度必須是大於0的整數。

-P:用於顯示萬用字元匹配模式的目錄和檔案,但是不管是否匹配,目錄一定顯示。

-I:用於顯示除被萬用字元匹配外的所有目錄和檔案。

【 顯示選項:】

-a:用於顯示隱藏檔案,預設不顯示。

-d:指定只顯示目錄。

-f:指定顯示全路徑。

-i:不縮排顯示。和-f一起使用很有用。

-p:用於顯示許可權位資訊。

-h:用於顯示大小。

-u:顯示username或UID(當沒有username時只能顯示UID了)。

-g:顯示groupname或GID。

-D:顯示檔案的最後一次Mtime。

--inodes:顯示inode號。

--device:顯示檔案或目錄所屬的裝置號。

-C:顯示顏色。

【 輸出選項:】

-o filename:指定將tree的結果輸出到filename檔案中。

下圖是一個較全的輸出結果。

3. 檔案的時間戳(atime/ctime/mtime)

檔案的時間屬性有三種:atime/ctime/mtime。atime是access time,即上一次的訪問時間;mtime是modify time,是檔案的修改時間;ctime是change time,也是檔案的修改時間,只不過這個修改時間計算的inode修改時間,也就是元資料修改時間。檔案還有一個建立時間(create time),大多數unix系統上都認為這是個無用的屬性,一般工具無法獲取這個時間,但是對於ext家族檔案系統,透過它的底層除錯工具debugfs可以獲取create time。

但mtime只有修改檔案內容才會改變,更準確的說是修改了它的data block部分;而ctime是修改檔案屬性時改變的,確切的說是修改了它的元資料部分,例如重新命名檔案,修改檔案所有者,移動檔案(移動檔案沒有改變datablock,只是改變了其inode指標,或檔名)等.當然,修改檔案內容也一定會改變ctime(修改檔案內容至少已經修改了inode記錄上的mtime,這也是元資料),也就是說mtime的改變一定會引起ctime的改變。

總結下:

(1).atime只在檔案被開啟訪問時才改變,若不是開啟檔案編輯內容(如重定向內容到檔案中),則ctime和mtime的改變不會引起atime的改變;

(2).mtime的改變一定引起ctime的改變,而訪問檔案時(例如cat),atime不一定會改變,所以atime"改變"(這個改變是假象,見下文分析)不一定會影響ctime。(見下面的relatime說明)

3.1 關於relatime

atime/ctime/mtime是Posix標準要求作業系統維護的時間戳資訊。但是每次將atime、ctime和mtime寫入到硬碟中(這些不會寫入快取,只要修改就是寫入磁碟,即使從快取讀取檔案內容也如此)效率很低。有多低?下圖是寫ctime消耗的時間,幾乎總要花費零點幾秒。

mtime要被修改,必然是修改了檔案內容,這時候將mtime寫入到硬碟中是應該的。但是atime和ctime呢?很多情況下根本用不到atime和ctime,在頻繁訪問檔案的時候,都要修改atime和ctime,這樣效率會降低很多很多,所以mount有個noatime選項來避免這種負面影響。

CentOS6引入了一個新的atime維護機制relatime:除非兩次修改atime的時間超過1天(預設設定86400秒),或者修改了mtime,否則訪問檔案的inode不會引起atime的改變。換句話說,當cat一個檔案的時候,它的atime可能會改變,但是你稍後再cat,它不會再改變。

由於cat檔案的時候atime可能不會改變,所以可能也就不會引起ctime的改變。

relatime維護的atime是可以控制的,詳見man mount的relatime和redhat官方手冊

-m:表示建立目錄時直接設定許可權

-p:表示遞迴建立多層目錄,即上層目錄不存在時也會直接將其創建出來(parent)

[root@xuexi ~]# mkdir /tmp/test1                 # 在tmp目錄中建立一個test1目錄[root@xuexi ~]# mkdir -m 711 /tmp/test2          # 直接建立test2時就賦予許可權711[root@xuexi ~]# mkdir -p /tmp/test3/test4/test5  # 建立test5,此時會將不存在的test3和test4目錄也建立好
4.2 建立檔案touch

touch file_name

[root@xuexi ~]# touch /tmp/test1/test1.txt [root@xuexi ~]# touch {1..10} # 建立檔名為1-10的檔案

多個{}還可以交換擴充套件。類似(a+b)(c+d)=ac+ad+bc+bd。

[root@xuexi ~]# touch {a,b}_{c,d} # 建立a_c、a_d、b_c、b_d四個檔案

touch主要是修改檔案的時間戳資訊,當touch的檔案不存在時就自動建立該檔案。可以使用 touch –c 來取消建立動作。

touch可以更改最近一次訪問時間(atime),最近一次修改時間(mtime),檔案屬性修改時間(ctime),這些時間可以透過命令stat file來檢視。其中ctime是檔案屬性上的更改,即元資料的更改,比如修改許可權。

touch -a修改atime,-m修改mtime,沒有修改ctime的選項。因為使用touch改變atime或mtime,同時也都會改變ctime,雖說atime並不總是會影響ctime(如cat檔案時)。

-t選項表示使用"[[CC]YY]MMDDhhmm[.ss]"格式的時間替代當前時間。

shell> touch -a -t 201212211212 file # 將file檔案的atime修改為2012年12月21號12點12分

-d選項表示使用指定的字串描述時間格式來替代當前時間,如"3 days ago","next Sunday"等很多種格式。

所以,touch命令選項說明如下:

-c:強制不建立檔案

-a:修改檔案access time(atime)

-m:修改檔案modification time(mtime)

-t:使用"[[CC]YY]MMDDhhmm[.ss]"格式的時間替代當前時間

-d:使用字串描述的時間格式替代當前時間

[root@xuexi ~]# rm -rf /tmp/test2

在刪除檔案之前,一定一定要確定是否真的刪除。最好使用rm -i(預設已經在~/.bashrc中定義了該別名),除非在指令碼中,否則不要輕易使用-f選項。已經有非常多的人不小心rm -rf *和rm -rf /NNNNN了。例如想刪除"rm –rf /abc*",結果習慣性的多敲了一個空格"rm –rf /abc *",完了。

5. 檢視檔案型別file命令

這是一個簡單檢視檔案型別的命令,檢視檔案是屬於二進位制檔案還是資料檔案還是ASCII檔案。

[root@xuexi tmp]# file /etc/aliases.db/etc/aliases.db: Berkeley DB (Hash, version 9, native byte-order)  # 資料檔案[root@xuexi tmp]# file ~/.bashrc/root/.bashrc: ASCII text    # ASCII檔案[root@xuexi tmp]# file /bin/ls/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped

除了基本的檢視檔案型別的功能外,file還有一個"-s"選項,是一個超強力的選項,可以檢視裝置的檔案系統型別。像有些分割槽工具如parted在分割槽時是可以指定檔案系統的(雖然不建議這麼做,CentOS 7的parted版本中已經取消了該功能),但在分割槽後格式化前,一般是比較難檢視該分割槽的檔案系統型別的,但使用file可以檢視到。

[root@server1 ~]# file -s /dev/sda1/dev/sda1: Linux rev 1.0 ext4 filesystem data (needs journal recovery) (extents) (huge files)[root@server1 ~]# file -s /dev/sda/dev/sda: x86 boot sector; GRand Unified Bootloader, stage1 version 0x3, boot drive 0x80, 1st sector stage2 0x7f86, GRUB version 0.94; partition 1: ID=0x83, active, starthead 32, startsector 2048, 512000 sectors; partition 2: ID=0x83, starthead 254, startsector 514048, 37332992 sectors; partition 3: ID=0x82, starthead 254, startsector 37847040, 4096000 sectors, code offset 0x48
6. 檔案/目錄複製和移動6.1 cp命令

cp [-apdriulfs] src dest # 複製單檔案或單目錄

cp [-apdriuslf] src1 src2 src3......dest_dir # 複製多檔案、目錄到一個目錄下

選項說明:

-p: 檔案的屬性(許可權、屬組、時間戳)也複製過去。如果不指定p選項,誰執行復制動作,檔案所有者和組就是誰。

-r或-R:遞迴複製,常用於複製非空目錄。

-d:複製的原始檔如果是連結檔案,則複製連結檔案而不是指向的檔案本身。即保持連結屬性,複製快捷方式本身。如果不指定-d,則複製的是連結所指向的檔案。

-a:a=pdr三個選項。歸檔複製,常用於備份。

-i:複製時如果目標檔案已經存在,詢問是否替換。

-u:(update)若目標檔案和原始檔同名,但屬性不一樣(如修改時間,大小等),則覆蓋目標檔案。

-f:強制複製,如果目標存在,不會進行-i選項的詢問和-u選項的考慮,直接覆蓋。

-l:在目標位置建立硬連結,而不是複製檔案本身。

-s:在目標位置建立軟連結,而不是複製檔案本身(軟連結或符號連結相當於windows的快捷方式)。

一般使用cp -a即可,對於目錄加上-r選項即可。

注意,bash內建命令在進行萬用字元匹配檔案的時候,"*"、"?"、"[]"是無法匹配到以"."開頭的檔案的,所以"*"不會匹配隱藏檔案。要通配隱藏檔案,使用"."代替上述幾種通配元字元即可,它能匹配除了"."和".."這兩個特殊目錄外的所有檔案。它並非萬用字元,而是表示當前目錄,顯然直接複製目錄,是可以將隱藏檔案複製走的。

例如,複製/etc/skel目錄下所有檔案包括隱藏檔案到/tmp目錄下。

cp -a /etc/skel/. /tmp

如果有重複檔案,則即使加上-f選項,也一樣會互動式詢問。解決方法可以是使用"yes"這個工具,它會不斷的生成y字母直到程序被殺掉,當然也可以自行指定要生成的字串。

yes | cp -a /etc/skel/. /tmp
6.2 scp命令和執行過程分析

scp是基於ssh的安全複製命令(security copy),它是從古老的遠端複製命令rcp改變而來,實現的是在host與host之間的複製,可以是本地到遠端的、本地到本地的,甚至可以遠端到遠端複製。注意,scp可能會詢問密碼。

如果scp複製的原始檔在目標位置上已經存在時(檔案同名),scp會替換已存在目標檔案中的內容,但保持其inode號。

如果scp複製的原始檔在目標位置上不存在,則會在目標位置上建立一個空檔案,然後將原始檔中的內容填充進去。

之所以解釋上面的兩句,是為了理解scp的機制,scp複製本質是隻是填充內容的過程,它不會去修改目標檔案的很多屬性,對於從遠端複製到另一遠端時,其機制見後文。

scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]file1 ... [[user@]host2:]file2

選項說明:

-1:使用ssh v1版本,這是預設使用協議版本

-2:使用ssh v2版本

-C:複製時先壓縮,節省頻寬

-l limit:限制複製速度,Kbit/s.

-o ssh_option:指定ssh連線時的特殊選項,一般用不上。偶爾在連線過程中等待提示輸入密碼較慢時,可以設定GSSAPIAuthentication為no

-P port:指定目標主機上ssh埠,大寫的字母P,預設是22埠

-p:複製時保持原始檔的mtime,atime,owner,group,privileges

-r:遞迴複製,用於複製目錄。注意,scp複製遇到連結檔案時,會複製連結的原始檔內容填充到目標檔案中(scp的本質就是填充而非複製)

-v:輸出詳細資訊,可以用來除錯或檢視scp的詳細過程,分析scp的機制

示例:

1.把本地檔案/home/a.tar.tz複製到遠端伺服器192.168.0.2上的/home/tmp,連線時使用遠端的root使用者:

scp /home/a.tar.tz [email protected]:/home/tmp/

2.目標主機不寫路徑時,表示複製到對方的家目錄下:

scp /home/a.tar.tz [email protected]

3.把遠端檔案/home/a.tar.gz複製到本機:

scp [email protected]:/home/a.tar.tz # 不接本地目錄表示複製到當前目錄scp [email protected]:/home/a.tar.tz /tmp # 複製到本地/tmp目錄下

4.複製遠端機器的/home/目錄到本地/tmp目錄下。

scp -r [email protected]:/home/ /tmp

5.從遠端主機192.168.100.60複製檔案到另一臺遠端主機192.168.100.62上。

scp [email protected]:/tmp/copy.txt [email protected]:/tmp

在遠端複製到遠端的過程中,例如在本地執行scp命令將A主機(192.168.100.60)上的/tmp/copy.txt複製到B主機(192.168.100.62)上的/tmp目錄下,如果使用-v選項檢視除錯資訊的話,會發現它的步驟類似是這樣的。

# 以下是從結果中提取的過程

# 首先輸出本地要執行的命令

Executing: /usr/bin/ssh -v -x -oClearAllForwardings yes -t -l root 192.168.100.60 scp -v /tmp/copy.txt [email protected]:/tmp

# 從本地連線到A主機

debug1: Connecting to 192.168.100.60 [192.168.100.60] port 22.

debug1: Connection established.

# 要求驗證本地和A主機之間的連線

debug1: Next authentication method: password

[email protected]'s password:

# 將scp命令列修改後傳送到A主機上

debug1: Sending command: scp -v /tmp/copy.txt [email protected]:/tmp

# 在A主機上執行scp命令

Executing: program /usr/bin/ssh host 192.168.100.62, user root, command scp -v -t /tmp

# 驗證A主機和B主機之間的連線

debug1: Next authentication method: password

[email protected]'s password:

# 從A主機上複製原始檔到最終的B主機上

debug1: Sending command: scp -v -t /tmp

Sending file modes: C0770 24 copy.txt

Sink: C0770 24 copy.txt

copy.txt 100% 24 0.0KB/s

# 關閉本地主機和A主機的連線

Connection to 192.168.100.60 closed.

也就是說,遠端主機A到遠端主機B的複製,實際上是將scp命令列從本地傳遞到主機A上,由A自己去執行scp命令。也就是說,本地主機不會和主機B有任何互動行為,本地主機就像是一個代理執行者一樣,只是幫助傳送scp命令列以及幫助顯示資訊。

其實從本地主機和主機A上的~/.ssh/know_hosts檔案中可以看出,本地主機只是添加了主機A的資訊,並沒有新增主機B的資訊,而在主機A上則添加了主機B的資訊。

6.3 mv命令

mv命令移動檔案和目錄,還可以用於重新命名檔案或目錄。

mv [-iuf] src dest # 移動單個檔案或目錄

mv [-iuf] src1 src2 src3 dest_dir # 移動多個檔案或目錄

選項說明:

--backup[=CONTROL]:如果目標檔案已存在,則對該檔案做一個備份,預設備份檔案是在檔名後加上波浪線,如/b.txt~

-b:類似於--backup,但不接受引數, 預設備份檔案是在檔名後加上波浪線,如/b.txt~

-f:如果目標檔案已存在,則強制覆蓋檔案

-i:如果目標檔案已存在,則提示是否要覆蓋,這是alias mv的預設選項

-n:如果目標檔案已存在,則不覆蓋已存在的檔案

如果同時指定了-f/-i/-n,則後指定的生效

-u:(update)如果原始檔和目標檔案不同,則移動,否則不移動

mv預設已經是遞迴移動,不需要-r引數。

6.4 mv的一個經典問題(mv的本質)

該問題涉及檔案系統操作檔案的機制,若不理解,請先深入學習檔案系統。

mv不能實現裡層同名目錄覆蓋外層同名目錄。如/tmp下有a目錄,a目錄裡還有a目錄,將不能實現/tmp/a/a移動到/tmp。

[root@toystory tmp]# tree -L 3 a -fCa└── a/a├── a/a/a2 directories, 1 file[root@toystory tmp]# mv a/* .mv: overwrite `./a'? ymv: cannot move `a/a' to `./a': Directory not empty
 
[root@toystory tmp]# mv -f /tmp/a/* /tmpmv: cannot move `/tmp/a/a' to `/tmp/a': Directory not empty

要解釋為何會如此,先說明移動和覆蓋動作的本質。

同文件系統下移動檔案實際上是修改目標檔案所在目錄的data block,向其中新增一行指向inode table中待移動檔案的inode的指標,如果目標路徑下有同名檔案,則會提示是否覆蓋,實際上是覆蓋指向該同名檔案的inode指標,由於同名檔案的inode記錄指標被覆蓋,就無法再找到該檔案的data block,所以該檔案被標記為刪除。

跨檔案系統移動檔案的本質:如果目標路徑下沒有同名檔案,則先為此檔案分配一個inode號,並在目標目錄的data block中新增一條指向該inode號的新記錄(是全新的),然後將檔案複製到目標位置,複製成功則刪除原始檔,複製失敗則保留原始檔;如果目標路徑下有同名檔案,則提示是否要覆蓋,如果選擇覆蓋,則將該同名檔案的inode指標指向新分配的inode號,然後將檔案複製到目標位置,複製成功則刪除原始檔,複製失敗則保留原始檔。

也就是說,同文件系統下移動檔案時,inode記錄不變(如inode號),當然,時間戳是一定會改變的,因為移動過程中修改了inode指向data block的指標。而跨檔案系統下移動檔案時,inode記錄完全改變,它是新新增的記錄。

但是現在不是重新命名為b,而是覆蓋/tmp/a,此時的動作按原理應該是先提示是否覆蓋,如果是,則刪除/tmp的data block中a對應的記錄,但由於此時/tmp/a目錄中還有檔案,該記錄無法刪除(因為如果要刪除了該記錄,代表刪除了/tmp/a整個目錄,而刪除整個/tmp/a目錄需要刪除裡面所有的檔案,在刪除它們之前的一個動作是把/tmp/a中的所有目錄和檔案的inode號標記為未使用,但此刻要移動的源目錄/tmp/a/a是在使用當中的),所以提示目錄非空而無法刪除,這裡所指的非空目錄指的是/tmp/a,而非是/tmp/a/a非空。

但是在Windows作業系統下,裡層目錄是可以直接覆蓋外層同名目錄的,這和檔案系統的行為有關。

其實在這個問題中,可以看出mv的很多原理。

7. 檢視檔案內容7.1 cat命令

輸出一個或多個檔案的內容。

cat [OPTION]... [FILE]...

選項說明

-n:顯示所有行的行號

-b:顯示非空行的行號

-E:在每行行尾加上$符號

-T:將TAB符號輸出為"^I"

-s:壓縮連續空行為單個空行

cat還有一個重要功能,允許將分行鍵入的內容輸入到一個檔案中去。

首先測試<<eof,這表示將鍵入的內容追加到標準輸入stdin中(不是從標準輸入中讀取), eof可以隨便使用其他符號代替。

[root@xuexi tmp]# cat <<eof> abc.com> eofabc.com

再測試<eof,發現沒有輸入的機會,並且此時只能使用eof作為符號,EOF或其他任何都不可以。因為<eof是讀取標準輸入,會將eof當成輸入檔案處理。所以一定要使用<<eof,這表示here document,而兩個eof正是document的起始和結束標誌。

[root@xuexi tmp]# cat <eof
[root@xuexi tmp]# cat <eox-bash: eox: No such file or directory[root@xuexi tmp]# cat <EOF-bash: EOF: No such file or directory

再進一步測試<<eof的功能,將鍵入的內容重定向到檔案而非標準輸入中。這時有兩種書寫方案:

第一種方案:>>filename<<eof或>filename<<eof

[root@xuexi ~]# cat >>/tmp/test.txt<<EOF # 輸入到這裡按回車鍵繼續輸入下一行> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 按回車輸入下一行> yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy # 按回車輸入下一行> zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz # 按回車輸入下一行> EOF # 頂格寫EOF結束輸入

第二種方案:<<eof>filename或<<eof>>filename

[root@xuexi tmp]# cat <<eof>log.txt> abc.com> eof

兩種方案結果是一樣的,且總是使用<<eof,只不過所寫的位置不同而已,不管寫在哪個位置,它都表示將鍵入的內容追加到標準輸入。然後再使用>filename或>>filename控制重定向的方式,將標準輸入中的內容重定向到filename檔案中。

7.2 tac

tac和cat字母正好是相反的,其作用也是和cat相反的,它會反向輸出行,將最後一行放在第一行的位置輸出,依此類推。但是,tac沒有顯示行號的引數。

shell> echo -e '1\n2\n3\n4\n5' | tac54321
7.3 head

head列印前面的幾行。

head [-n num] | [-num] [-v] filename

-n:顯示前num行;如果num是負數,則顯示除了最後|num|(絕對值)行的其餘所有行,即顯示前"總行數 - |num|"

-v:會顯示出檔名

-n num是顯示檔案的前num行,num可以是+/-或不加正負號的整數,如果是正整數或不寫+號,則顯示前num行。如果是負整數,則從後向前數num行,並列印除了這些行的前面所有的行,即列印除了最後num行的所有行,也即總行數減num的前正數行。不寫-n時預設是前10行。正整數時"-n num"可以直接簡寫"-num"。

不管怎麼樣,它取的都是前幾行,哪怕是負整數也是前幾行。

示例:

[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | head     # 取出預設前10行,但總共才有5行。12345[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | head -2     # 取出前2行12

或者

[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | head -n 2 # 取出前2行12[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | head -n -1 # 取出前5-1=4行1234
7.4 tail

tail和head相反,是顯示後面的行,預設是後10行。

tail [OPTION]... [FILE]...

選項說明:

-n:輸出最後num行,如果使用-n +num則表示輸出從第num行開始的所有行

-f:監控檔案變化

--pid=PID:和-f一起使用,在給定PID的程序死亡後,終止檔案監控

-v:顯示檔名

"-n -num"或"-num"或"-n num"(num為正整數)表示輸出最後的num行。使用"-n +num"(num為正整數)則表示輸出從第num行開始的所有行。

[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | tail -3         # 等價於 tail -n 3和tail -n -3345[root@xuexi tmp]# seq 6 | tail -n +3       # 列印除了前3-1=2行的所有行3456

tail還有一個重要的引數-f,監控檔案的內容變化。當一個使用者不斷修改某個檔案的尾部,另一個使用者就可以透過這個命令來重新整理並顯示這些修改後的內容。

7.5 nl

以行號的方式檢視內容。

常用"-b a",表示不論是否空行都顯示行號,等價於cat -n;不寫選項時,預設"-b t",表示空行不顯示行號,等價於cat -b。

[root@xuexi ~]# nl /etc/issue # 預設空行不顯示行號1 CentOS release 6.6 (Final)2 Kernel \r on an \m[root@xuexi ~]# nl -b a /etc/issue1 CentOS release 6.6 (Final)2 Kernel \r on an \m3
7.6 more和less

按頁顯示檔案內容。使用more時,使用/搜尋字串,按下n或N鍵表示向下或向上繼續搜尋。使用less時,還多了一個搜尋功能,使用?搜尋字串,同樣,使用n或N鍵可以向上或向下繼續搜尋。

7.7 比較檔案內容
shell> diff file1 file2shell> vimdiff file1 file2
8. 檔案查詢類命令

搜尋檔案的路徑在何處以及檔案的名稱為何。

8.1 which

顯示命令或指令碼的全路徑,預設也會將命令的別名顯示出來。

shell> which mvalias mv='mv -i'       /bin/mv
8.2 whereis

找出二進位制檔案、原始檔和man文件檔案。

shell> whereis cd

cd: /usr/bin/cd /usr/share/man/man1/cd.1.gz /usr/share/man/man1p/cd.1p.gz /usr/share/man/mann/cd.n.gz

8.3 whatis

列出給定命令(並非一定是命令)的man文件資訊。

shell> whatis passwdsslpasswd (1ssl) - compute password hashespasswd (1) - update user's authentication tokenspasswd (5) - password file

根據上面的結果,執行:

man 1 passwd # 獲取passwd命令的man文件man 5 passwd # 獲取password檔案的man文件,檔案類的man文件說明的是該檔案中各配置項意義man sslpasswd # 獲取sslpasswd命令的man文件,實際上是openssl passwd的man文件
8.4 locate

沒什麼好說的。

8.5 find

內容太多,使用兩篇單獨的文章解釋

Linux find常用用法示例

Linux find執行機制詳解

12
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 程式設計師基礎知識:記憶體對齊是什麼?為什麼需要記憶體對齊