ls * 、 ls ** 和 ls *** 的結果
我知道使用該命令
ls
將列出所有目錄。但是該ls *
命令有什麼作用?我使用它,它只列出目錄。前面的星號是否ls
意味著它將列出目錄的深度?
ls
列出作為參數傳遞的目錄的文件和內容,如果沒有給出參數,則列出目前目錄。它還可以傳遞一些影響其行為的選項(詳情請參閱man ls
)。如果
ls
傳遞了一個名為 的參數*
,它將*
在目前目錄中查找一個文件或目錄,並像其他任何文件一樣列出它。ls
不會*
以任何其他方式對待角色。但是,如果
ls *
是shell命令行,即Unix shell 語言中的程式碼,那麼 shell 將*
根據其通配(也稱為文件名生成或文件名/路徑名擴展)規則對其進行擴展。雖然不同的 shell 支持不同的 globbing 運算符,但它們中的大多數都同意最簡單的一個
*
。*
as 模式表示任意數量的字元,因此*
aglob
將擴展為目前目錄中與該模式匹配的文件列表。但是有一個例外,.
文件名中的前導點 ( ) 字元必須明確匹配,因此*
實際上擴展為不以.
(按詞法順序)開頭的文件和目錄列表。例如,如果目前目錄包含名為
.
、..
、和的文件.foo
,shell 將擴展為兩個參數以傳遞給:和,因此就好像您輸入了:-l``foo bar``*``ls``-l``foo bar
ls -l "foo bar"
或者
'ls' "-l" foo\ bar
這是執行完全相同命令的三種方式。在所有 3 種情況下,
ls
命令(可能會從/bin/ls
中提到的目錄查找中執行$PATH
)將傳遞這 3 個參數:“ls”、“-l”和“foo bar”。順便說一句,在這種情況下,
ls
將把第一個(嚴格來說是第二個)作為一個選項。現在,正如我所說,不同的 shell 有不同的萬用字元。幾十年前,
zsh
引入了**/
操作符¹,這意味著匹配任何級別的子目錄,簡稱(*/)#
和***/
相同,除了它在下降目錄時遵循符號連結。幾年前(2003 年 7 月
ksh93o+
),ksh93
決定複製該行為,但決定將其設為可選,並且僅涵蓋該**
情況(不是***
)。此外,雖然**
單獨在 ² 中並不特殊(只是意味著與其他傳統 shell 中zsh
的相同,因為意味著任意數量的字元後跟任意數量的字元),但在 ksh93 中,意味著與(因此目前以下的任何文件或目錄相同)一個(不包括隱藏文件)³。*``**``**``**/*
bash``ksh93
幾年後複製(2009 年 2 月,bash 4.0),語法相同,但有一個不幸的區別:bash**
就像zsh
‘s一樣***
,即它在遞歸到子目錄時遵循符號連結,這通常不是你想要的可能會產生令人討厭的副作用。它在 bash-4.3 中部分修復,因為仍然遵循符號連結,但遞歸停止在那裡。它在 5.0 中完全修復。
yash``**
在 2008 年的 2.0 版中添加,使用該extended-glob
選項啟用。它的實現更接近於zsh
‘s,**
僅此一點並不特別。在 2.15 版(2009 年)中,它添加了***
like inzsh
和兩個自己的擴展:.**
並.***
在遞歸時包含隱藏的目錄(在 中zsh
,D
glob 限定符(如在 中**/*(D)
)將考慮隱藏文件和目錄,但如果你只想遍歷隱藏dirs 但不展開隱藏文件,您需要((*|.*)/)#*
或**/[^.]*(D)
)。fish shell也支持
**
。與早期版本一樣bash
,它在向下目錄樹時遵循符號連結。然而,在那個 shell 中**/*
與**
. 更多的是可以跨越多個目錄**
的擴展。*
Infish
,**/*.c
will matcha/b/c.c
but nota.c
, whilea**.c
will matcha.c
andab/c/d.c
andzsh
’s**/.*
例如必須寫.* **/.*
。在那裡,***
被理解為**
跟*
so一樣**
。
tcsh
還在 V6.17.01(2010 年 5 月)中添加了一個globstar
選項,並同時支持**
和***
à lazsh
。所以 in
tcsh
,bash
andksh93
, (當相應的選項被啟用 (globstar
)) orfish
,**
展開目前目錄下的所有文件和目錄, 和for***
一樣, 一個遍歷for的符號連結, 和in一樣(雖然它是這些 shell 的未來版本也將遍歷符號連結,這並非不可能)。**``fish``**``tcsh``globstar``*``bash``ksh93
在上面,您會注意到需要確保沒有任何擴展被解釋為選項。為此,你會這樣做:
ls -- *
或者:
ls ./*
有一些命令(無關緊要
ls
),其中第二個更可取,因為即使使用--
某些文件名也可能會被特殊處理。例如,-
大多數文本實用程序cd
和pushd
包含該=
字元的文件名都是這種awk
情況。前置./
所有參數會消除它們的特殊含義(至少對於上述情況)。還應該注意的是,大多數 shell 都有許多影響通配行為的選項(例如是否忽略點文件、排序順序、如果沒有匹配項怎麼辦……),另請參見
$FIGNORE
參數ksh
csh
此外,在除、和之外的每個 shell中tcsh
,如果通配模式與任何文件都不匹配,則該模式將作為未擴展的參數傳遞,這會導致混淆並可能導致錯誤。例如,如果目前目錄中沒有非隱藏文件fish``zsh
ls *
實際上會
ls
用兩個參數ls
和呼叫*
。而且由於根本沒有文件,所以也沒有呼叫,你會看到來自ls(不是 shell)*
的錯誤消息,比如: ,眾所周知,這會讓人們認為它實際上是在擴展 glob。ls: cannot access *: No such file or directory``ls
在以下情況下問題更嚴重:
rm -- *.[ab]
如果目前目錄中沒有
*.a
nor*.b
文件,那麼您最終可能會刪除*.[ab]
錯誤呼叫的文件(csh
,tcsh
,並且zsh
會報告不匹配錯誤並且不會呼叫rm
(並且fish
不支持[...]
萬用字元))。如果您確實想將文字傳遞
*
給,則必須以某種方式ls
引用該字元,如or或。在類似 POSIX 的 shell 中,可以使用or完全禁用萬用字元(後者不工作,除非在/仿真中)。*``ls \*``ls '*'``ls "*"``set -o noglob``set -f``zsh``sh``ksh
¹ 雖然
(*/)#
一直受到支持,但它首先是..../
在 zsh-2.0(可能之前)中人手不足,然後是在 2.1 中,然後在 2.2 中(1992 年初)****/
獲得其最終形式**/
²
globstarshort
選項, 已被添加(在 2015 年)以允許**
和被分別***
用來代替**/*
和***/*
³ 另請參閱ksh93
globstar
設計的這些更多奇怪之處,其中一些被bash
. .