
我想使用通配符“*”來 grep 所有 .txt 檔案。
我嘗試了這個命令(以及沒有引號“”)但失敗了。
ls | grep "*.txt"
有趣的是,如果我在 grep 命令中放入與目錄中的 .txt 檔案相對應的另一個字符,它就會起作用
>>ls | grep s*.txt
sample.txt
我知道這ls *.txt
會起作用,但我對 grep 命令的性質有點驚訝。有人可以幫助我為什麼會發生這種情況嗎?
是不是因為grep使用了正規表示式,請幫忙。
答案1
在正規表示式中,*
意味著“任意數量的前一項”,而不是“任意數量的任意字元”,就像在 shell 模式中那樣。並.
表示“任何單一字元”。因此,要查找“任何內容,後跟文字.txt
”,您可以使用.*\.txt
.或者只是\.txt
,因為通常正規表示式匹配會在行中的任何位置搜尋匹配項。然後,\.txt
也會符合類似 的檔名foo.txtgz
,因為.txt
不必位於最後。您需要\.txt$
將模式鎖定到行尾。
正規表示*.txt
式要么是無意義的、是錯誤的,要么是查找字面星號,具體取決於實現以及您使用的是基本正則表達式 ( grep
) 還是擴展正則表達式 ( grep -E
)。最好不要使用它。
另一方面,s*.txt
會尋找“任意數量的字母s
,然後是任意單個字符,然後是文字txt
”。這是一個更有效的正規表示式,但是...仍然不匹配sample.txt
。
相反,第二個命令中發生的情況是,由於s*.txt
未加引號,shell 會在看到它s*.txt
之前展開grep
它。如果唯一符合的檔案是sample.txt
,則grep
在 的輸出中尋找該檔案ls
。 (如果有多個匹配的檔案名,第一個將被視為模式,其餘的將作為檔案名稱進行grep
讀取。在這種情況下,它將忽略來自管道的輸入。)
但是,ls
也可以獲得文件列表,因此雖然您可以使用
ls | grep '\.txt'
要取得任何.txt
文件,使用它可能會更容易
ls *.txt
反而。
答案2
部分原因是因為grep
使用了正規表示式(事實上,這就是re
名稱中的代表的意思 - 它是G局部的r規則的e表達p列印).
正規表示式中的通配符與shell 通配符中的通配符*
不同。*
在正規表示式中,*
表示「零個或多個先前定義的物件」。然而,.
是也通配符,意思是「一個字元」。
在 shell glob 中,*
表示「零個或多個字元」。 .
根本不是通配符。
當您grep
查找模式時"*.txt"
,您正在尋找零個或多個任何內容,後面跟著一個字符,最後是文字字串txt
。
當您grep
使用模式"s*.txt"m you are looking for a literal
s , followed by zero or more
s s, followed by any character, followed by the literal string
txt`.
這就是為什麼您在正規表示式中會發現的一個常見現像是.*
,這意味著「任何字元之一後跟零個或多個任何字元」。正規表示式「實際上是除零字元之外的任何字元組合」。
當您ls *.txt
告訴 shell「尋找與 glob 模式相符的任何檔案名稱」時*.txt
,請在此處列出它們,並將它們作為參數提供給ls
命令。
答案3
請注意 grep 正在搜尋文件內容第一個參數是搜尋模式,其他參數解釋為要查看的文件
grep -H -o
當使用標誌或將您的腳本放入grep
腳本並運行它以bash -x script
查看 shell glob 在作為參數傳遞之前如何擴展時,您會變得更加清楚