第1章 Linux文件類基礎命令


1. 關於路徑和通配符

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

路徑展開符號:

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

切換路徑用cd命令;

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

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

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

[root@xuexi tmp]# basename /etc/shadow
shadow
[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 dotglob
ls *

有時想要遞歸到目錄內部,又想要匹配文件名,例如想要遞歸找出多層目錄/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 /tmp
drwxr-xr-x  2 root root 4096 Mar 26 16:44 test1

可以查出7列屬性。

image

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文件中。

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

image

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的改變。

對目錄而言,考慮目錄文件的data block,可知在目錄中創建、刪除文件以及目錄內其他任意文件操作都會改變mtime,因為目錄里的任何東西都是目錄中的內容;而目錄的ctime,除了目錄的mtime引起ctime改變之外,對目錄本身的元數據修改也會改變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官方手冊

4. 文件/目錄的創建和刪除

4.1 創建目錄mkdir

mkdir [-mp] 目錄名

-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:使用字符串描述的時間格式替代當前時間

4.3 刪除文件/目錄

rm [-rfi] file_name

-r:表示遞歸刪除,刪除目錄時需要加此參數

-i:詢問是否刪除(yes/no)

-f:強制刪除,不進行詢問

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

刪除空目錄時還可以使用rmdir。

在刪除文件之前,一定一定要確定是否真的刪除。最好使用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 root@192.168.0.2:/home/tmp/

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

scp /home/a.tar.tz root@192.168.0.2

3.把遠程文件/home/a.tar.gz拷貝到本機:

scp root@192.168.0.2:/home/a.tar.tz # 不接本地目錄表示拷貝到當前目錄

scp root@192.168.0.2:/home/a.tar.tz /tmp # 拷貝到本地/tmp目錄下

4.拷貝遠程機器的/home/目錄到本地/tmp目錄下。

scp -r root@192.168.0.2:/home/ /tmp

5.從遠程主機192.168.100.60拷貝文件到另一台遠程主機192.168.100.62上。

scp root@192.168.100.60:/tmp/copy.txt root@192.168.100.62:/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 root@192.168.100.62:/tmp

 

# 從本地連接到A主機

debug1: Connecting to 192.168.100.60 [192.168.100.60] port 22.

debug1: Connection established. 

 

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

debug1: Next authentication method: password

root@192.168.100.60's password:

 

# 將scp命令行修改后發送到A主機上

debug1: Sending command: scp -v /tmp/copy.txt root@192.168.100.62:/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

root@192.168.100.62'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的信息。

image

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 -fC

a
└── a/a
├── a/a/a
2 directories, 1 file

[root@toystory tmp]# mv a/* .
mv: overwrite `./a'? y
mv: cannot move `a/a' to `./a': Directory not empty
 
[root@toystory tmp]# mv -f /tmp/a/* /tmp mv: 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記錄完全改變,它是新添加的記錄。

再考慮上面的問題,同文件系統下移動文件時先在目標位置/tmp的data block中添加一條記錄,如果同名則提示覆蓋,覆蓋時會先刪除/tmp的data block中的a對應的記錄,再添加將要移動文件的記錄。從上面的結果也可以看出是先提示覆蓋再提示目錄非空的錯誤。

設想下,如果/tmp/a/a移動到/tmp下並重命名為b,則其動作是直接向/tmp的data block中添加b的記錄,如果此時正好/tmp下已有b目錄,則先刪除/tmp的data block中b目錄對應的記錄,再添加移動后的b記錄。

但是現在不是重命名為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
> eof
abc.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' | tac
5
4
3
2
1

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行。
1
2
3
4
5

[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | head -2     # 取出前2行
1
2

或者

[root@xuexi ~]# echo -e '1\n2\n3\n4\n5' | head -n 2 # 取出前2行
1
2

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

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 -3
3
4
5

[root@xuexi tmp]# seq 6 | tail -n +3       # 打印除了前3-1=2行的所有行
3
4
5
6

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/issue
1 CentOS release 6.6 (Final)
2 Kernel \r on an \m
3

7.6 more和less

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

7.7 比較文件內容

shell> diff file1 file2

shell> vimdiff file1 file2

8. 文件查找類命令

搜索文件的路徑在何處以及文件的名稱為何。

8.1 which

顯示命令或腳本的全路徑,默認也會將命令的別名顯示出來。

shell> which mv

alias 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 passwd

sslpasswd (1ssl) - compute password hashes
passwd (1) - update user's authentication tokens
passwd (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運行機制詳解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM