Bash
在函式內部設置 -f
我有一個包含文件的目錄
file1.c
,file2.c
並且file3.c
. 命令find
輸出:$find -name "*.c" ./file1.c ./file2.c ./file3.c
然後我想使用
find
不帶引號的.*c
. 為此,我使用set -f
:$echo $- # check current options himBHs $set -f $echo $- # check that f option is set fhimBHs $find -name *.c ./file1.c ./file2.c ./file3.c $set +f # unset f option
我在函式中嘗試了相同的命令
.bashrc
:find() { set -f eval command find $@ set +f }
但測試它給出了錯誤:
$ . ~/.bashrc && find -name *c find: paths must precede expression: file1.c Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression
函式中出現此錯誤的原因是什麼?
find
版本:GNU 4.6.0
你沒有說,但你必須像這樣呼叫函式:
find -name *.c
但是 globbing 還沒有關閉,所以 shell
*.c
在呼叫之前擴展了。所以find
命令看到’-name’後跟三個參數,因此是錯誤消息。您可以使用反斜杠代替引號。
find -name \*.c
您的函式禁用文件名通配,但您使用外殼擴展的 glob 呼叫它(文件名通配在您呼叫它的外殼中未關閉)。
換句話說,你命令中的 glob
find -name *c
在呼叫您的
find
函式之前展開。這會導致find
實用程序無法理解的函式內部呼叫。您可以通過使用帶引號的參數呼叫您的函式來解決這個問題:
find -name "*c"
但請注意,現在該功能完全沒用,因為它只是複制了您已經輸入的命令。
除了無用之外,它也是錯誤的*。由於
$@
在您的程式碼中未引用,因此它會將參數拆分為空格(預設情況下)。這意味著您不能*使案例如find -name "* *"
查找其中包含空格的名稱。
另請注意,由於
eval
,shell 將對$@
. 這意味著find -name '$(echo hello)'
不會找到名為
$(echo hello)
but的文件hello
。另一件事是,如果呼叫 shell已經使用
set -f
,那麼這將被函式禁用。讓我們創建一個有用的函式。查找多個文件名模式的函式,例如:
myfind "*.c" "*.txt" "* *"
我們希望上面的命令返回以
.c
或.txt
或包含空格的路徑名。這是功能:
myfind () { # Replace each positional parameter "$pattern" # with -o -name "$pattern" for pattern do set -- "$@" -o -name "$pattern" shift done shift # shift off the initial "-o" find . "$@" }
鑑於上述函式呼叫,它將最終執行
find . -name '*.c' -o -name '*.txt' -o -name '* *'
如果您更習慣將
bash
數組用於列表,並且不介意更多輸入:myfind () { local -a args # Build the argument list for find by adding # -o -name "$pattern" # for each positional parameter for pattern do args+=( -o -name "$pattern" ) done args=( "${args[@]:1}" ) # remove the initial "-o" find . "${args[@]}" }