'*'ワイルドカードをスクリプトの変数を介してfindコマンドのパスパラメーターに渡す方法は?


9

を使用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

もう1つの例を示します。

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

予想通り:

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

私が試したすべてのバリエーションはエラーを返します。

回避策がありますが、あまりにも多くのフォルダーが返されるため、潜在的に危険です。すべてのスペースを次のように疑問符(1文字のワイルドカード)に変換します。

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れます。

自分がやろうとしていることをどのように達成できますか?グーグルは私を助けていません:(


@KasiyA私はbashを使用しています。以前にその構造を見たことがないので、あなたは何か他のものを使用しているに違いありません。SEARCH: command not foundコマンドfind -printを実行すると、コマンドが実行されます。
Paddy Landau

暗闇の中でのショットですが、引用はどうですか?find "${SEARCH}" -print
Alaa Ali

@AlaaAliいいえ、機能しません。引用すると、Bashがワイルドカードを使用できなくなるためです。特に(私の例では)という名前のパスを探しますte*/'my files'/more
Paddy Landau

回答:


9

まったく同じコマンドがスクリプトで正常に機能するはずです。

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

変数として必要な場合は、少し複雑になります。

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

警告:

このevalような使用は安全ではなく、ファイル名に特定の文字が含まれていると、任意の、場合によっては有害なコードが実行される可能性があります。詳細については、bash FAQ 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

globstarbashのオプションを使用すると、使用することができます**再帰的に一致させるために:

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.

dotfile(隠しファイル)を検索して含めるように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
terdonから寄せられた有益なコメントのために、これを回答として設定しました(他のユーザーからの有益なコメントを忘れないでください)。スクリプトを整理しようとする代わりに、コマンドラインでBashのグロビング機能を使用して、スクリプトに複数のパスを渡しました。うまくいきます。
Paddy Landau

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/'

賢いアイデアですが、悲しいかな、それは機能しません。どうして?パス自体が変数に保持されているため、したがって、INPUTPATH='te*/my files/moreそしてSEARCH=(${INPUTPATH})。これをどのように変更しても、結局は機能しない結果になります。これは不可能のようです!
Paddy Landau

もちろんこれはすべて本当ですが、OPはスクリプトでそれを行う必要があります。ワイルドカードの展開が大幅に複雑になり、これが機能しないため、状況が変わります。
terdon 2014年

@PaddyLandauその場合、なぜfind-pathフィルターを使用できないのですか?ワイルドカードを使用しており、拡張する必要はありません。
muru、2014年

@muru面白いですね。知りませんでした-path。しかし、過去10分間で、答えを見つけましたeval。よりシンプルなようです-path
Paddy Landau

2
@terdonとmuruとみんな:ありがとう。私はあなたがすべて言ったことを聞いたので、私は自分のスクリプトに1つのことを行わせ、Bashグロビングに複数のファイルまたはスクリプトへのパスを渡させるべきであることに気付きました。このようにスクリプトを変更しました。これはうまく機能し、Linuxの哲学によく適合します。ありがとうございました!
Paddy Landau

0

ようやく答えがわかりました。

すべてのスペースにバックスラッシュを追加します。

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

この時点で、SEARCHが含まれていますte*/my\ files/more

次に、を使用しますeval

eval find ${SEARCH} -print

とても簡単です!を使用evalすると${SEARCH}、変数からの解釈がバイパスされます。



@terdon警告ありがとうございます。ふりだしに戻る!
Paddy Landau

ええ、これは驚くほどトリッキーです。私は別のアプローチで私の答えを更新しました、代わりにグロビングを使用しないのはなぜですか?それでもうまくいかない場合は、UnixとLinuxに新しい質問を投稿して、最終的な目的が何か、なぜパターンを変数として持つ必要があるのか​​を説明することをお勧めします。このタイプのものは、そこでより良い答えを得るのに似ています。
terdon 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.