如何透過腳本中的變數將「*」通配符傳遞給 find 指令的路徑參數?

如何透過腳本中的變數將「*」通配符傳遞給 find 指令的路徑參數?

我想用來find在一組受通配符限制的資料夾中尋找文件,但路徑名稱中有空格。

從命令列來看,這很容易。以下範例均有效。

find  te*/my\ files/more   -print
find  te*/'my files'/more  -print
find  te*/my' 'files/more  -print

這些將在例如terminal/my files/more和中查找文件tepid/my files/more

但是,我需要將其作為腳本的一部分;我需要的是這樣的:

SEARCH='te*/my\ files/more'
find ${SEARCH} -print

不幸的是,無論我做什麼,我似乎都無法在find腳本中的命令中混合通配符和空格。上面的範例傳回以下錯誤(請注意意外的雙反斜線):

find: ‘te*/my\\’: No such file or directory
find: ‘files/more’: No such file or directory

嘗試使用引號也會失敗。

SEARCH="te*/'my files'/more"
find ${SEARCH} -print

這將傳回以下錯誤,忽略引號的含義:

find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory

這裡還有一個例子。

SEARCH='te*/my files/more'
find ${SEARCH} -print

正如預期的那樣:

find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory

我嘗試過的每個變體都會返回錯誤。

我有一個解決方法,這有潛在危險,因為它返回太多資料夾。我將所有空格轉換為問號(單字元通配符),如下所示:

SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?}       # Convert every space to a question mark.
find ${SEARCH} -print

這相當於:

find te*/my?files/more -print

這不僅會傳回正確的資料夾terse/myxfiles/more,還會傳回不應該的資料夾。

我怎樣才能實現我想做的事情? Google沒有幫助我:(

答案1

完全相同的命令在腳本中應該可以正常工作:

#!/usr/bin/env bash
find  te*/my\ files/ -print

如果你需要要將其作為變量,它會變得更加複雜:

#!/usr/bin/env bash
search='te*/my\ files/'
eval find "$search" -print

警告:

這樣使用eval並不安全,如果您的檔案名稱可以包含某些字符,則可能會導致執行任意且可能有害的代碼。看bash 常見問題 48了解詳情。

最好將路徑作為參數傳遞:

#!/usr/bin/env bash
find "$@" -name "file*"

另一種方法是完全避免find並使用 bash 的擴展通配符功能和通配符:

#!/usr/bin/env bash
shopt -s globstar
for file in te*/my\ files/**; do echo "$file"; done

bashglobstar選項可讓您使用**遞歸匹配:

globstar
      If set, the pattern ** used in a pathname expansion con‐
      text will match all files and zero or  more  directories
      and  subdirectories.  If the pattern is followed by a /,
      only directories and subdirectories match.

要使其 100% 類似於查找並包含點文件(隱藏文件),請使用

#!/usr/bin/env bash
shopt -s globstar
shopt -s dotglob
for file in te*/my\ files/**; do echo "$file"; done

您甚至可以echo直接使用它們而無需循環:

echo te*/my\ files/**

答案2

數組怎麼樣?

$ tree Desktop/ Documents/
Desktop/
└── my folder
    └── more
        └── file
Documents/
└── my folder
    ├── folder
    └── more

5 directories, 1 file
$ SEARCH=(D*/my\ folder)
$ find "${SEARCH[@]}" 
Desktop/my folder
Desktop/my folder/more
Desktop/my folder/more/file
Documents/my folder
Documents/my folder/more
Documents/my folder/folder

(*)擴展為與通配符匹配的任何內容的數組。並"${SEARCH[@]}"擴展到數組 ( [@]) 中的所有元素,每個元素都單獨引用。

後來,我意識到發現自己應該有能力做到這一點。就像是:

find . -path 'D*/my folder/more/'

答案3

現在有點過時了,但是,如果這可以幫助任何人解決這個問題,那麼只要擴展路徑名中沒有特殊字符代替星號,使用 RE 的整理符號而不在 find 命令行參數中[[.space.]]引用變量就可以工作。$SEARCH

set -x
mkdir -p te{flon,nnis,rrine}/my\ files/more
SEARCH=te*/my[[.space.]]files/more
find $SEARCH

給出以下結果:

+ mkdir -p 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more'
+ SEARCH='te*/my[[.space.]]files/more'
+ find 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more'
teflon/my files/more
tennis/my files/more
terrine/my files/more

為了防止出現不需要的字符,可以*用任何整理元素(字符)替換星號 ( ):

set -x
mkdir -p -- te{,-,_}{flon,nnis,rrine}/my\ files/more
SEARCH=te[[:alnum:][.space.][.hyphen.][.underscore.]]*/my[[.space.]]files/more
find $SEARCH

給出以下結果:

+ mkdir -p -- 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more' \
'te-flon/my files/more' 'te-nnis/my files/more' 'te-rrine/my files/more' \
'te_flon/my files/more' 'te_nnis/my files/more' 'te_rrine/my files/more'
+ SEARCH='te[[:alnum:][.space.][.hyphen.][.underscore.]]*/my[[.space.]]files/more'
+ find 'te-flon/my files/more' 'te_flon/my files/more' 'teflon/my files/more' \
'te-nnis/my files/more' 'te_nnis/my files/more' 'tennis/my files/more' \
'te-rrine/my files/more' 'te_rrine/my files/more' 'terrine/my files/more'
te-flon/my files/more
te_flon/my files/more
teflon/my files/more
te-nnis/my files/more
te_nnis/my files/more
tennis/my files/more
te-rrine/my files/more
te_rrine/my files/more
terrine/my files/more

請注意,要縮短該行, 可以用or[.hyphen.]替換 ,並且 可以用or替換。[.-.]-[.underscore.][._.]_



\為了方便閱讀,我自己添加了帶有反斜線()的截斷行。

答案4

我終於找到答案了。

在所有空格中添加反斜線:

SEARCH='te*/my files/more'
SEARCH=${SEARCH// /\\ }

此時,SEARCH包含te*/my\ files/more.

然後,使用eval.

eval find ${SEARCH} -print

就這麼簡單!使用繞過來自變數eval的解釋。${SEARCH}

相關內容