Shell
擴展為點文件但不擴展為“..”的外殼文件名模式?
最近,我遇到了一個小意外,原因是 shell 模式以一種意想不到的方式擴展。我想更改目錄中一堆點文件的所有者
/root
,所以我做了chown -R root .*
自然,
.*
擴大到..
哪個是一場災難。我知道
bash
可以通過調整一些 shell 選項來改變這種行為,但是在預設設置下,是否有任何模式可以擴展到目錄中的每個點文件,但不能擴展到.
and..
?
Bash、ksh 和 zsh 有更好的解決方案,但在這個答案中,我假設一個 POSIX shell。
該模式
.[!.]*
匹配所有以點開頭後跟非點字元的文件。(請注意,[^.]
某些 shell 支持但不是全部,萬用字元模式中字元集補碼的可移植語法是[!.]
。)因此,它不包括.
and..
,但也包括以兩個點開頭的文件。該模式..?*
處理以兩個點開頭的文件,而不僅僅是..
.chown -R root .[!.]* ..?*
這是匹配所有文件的經典模式集:
* .[!.]* ..?*
這種方法的一個限制是,如果其中一個模式不匹配,則將其傳遞給命令。在腳本中,當要匹配目錄中除
.
and之外的所有文件時..
,有幾種解決方案,都比較麻煩:
- 用於
* .*
列舉所有條目,並在循環中排除.
和。..
一種或兩種模式可能不匹配,因此循環需要檢查每個文件是否存在。您有機會根據其他標准進行過濾;例如,-h
如果您想跳過懸空符號連結,請刪除測試。for x in * .*; do case $x in .|..) continue;; esac [ -e "$x" ] || [ -h "$x" ] || continue somecommand "$x" done
- 一個更複雜的變體,其中命令只執行一次。請注意,位置參數被破壞(POSIX shell 沒有數組);如果這是一個問題,請將其放在單獨的函式中。
set -- for x in * .[!.]* ..?*; do case $x in .|..) continue;; esac [ -e "$x" ] || [ -h "$x" ] || continue set -- "$@" "$x" done somecommand "$@"
- 使用
* .[!.]* ..?*
三聯畫。同樣,一個或多個模式可能不匹配,因此我們需要檢查現有文件(包括懸空符號連結)。for x in * .[!.]* ..?*; do [ -e "$x" ] || [ -h "$x" ] || continue somecommand "$x" done
- 使用
* .[!.]* ..?*
trypitch,並為每個模式執行一次命令,但前提是它匹配某些內容。這只會執行一次命令。請注意,位置參數已被破壞(POSIX shell 沒有數組),如果這是一個問題,請將其放在單獨的函式中。set -- * [ -e "$1" ] || [ -h "$1" ] || shift set -- .[!.]* "$@" [ -e "$1" ] || [ -h "$1" ] || shift set -- ..?* "$@" [ -e "$1" ] || [ -h "$1" ] || shift somecommand "$@"
- 使用
find
. 使用 GNU 或 BSD find,使用選項-mindepth
和-maxdepth
. 使用 POSIX find,它有點棘手,但可以完成。這種形式的優點是可以輕鬆地允許一次執行命令而不是每個文件一次(但這不能保證:如果生成的命令太長,該命令將分幾批執行)。find . -name . -o -exec somecommand {} + -o -type d -prune