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
試したすべてのバリエーションでエラーが返されます。
回避策はありますが、あまりにも多くのフォルダーが返されるため、潜在的に危険です。次のように、すべてのスペースを疑問符 (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
、本来返されるべきではない も返されます。
私がやろうとしていることをどうすれば達成できるでしょうか? Google は私を助けてくれませんでした :(
答え1
まったく同じコマンドがスクリプトでも問題なく動作するはずです:
#!/usr/bin/env bash
find te*/my\ files/ -print
もし、あんたが必要それを変数として持つと、少し複雑になります。
#!/usr/bin/env bash
search='te*/my\ files/'
eval find "$search" -print
警告:
このような使用方法はeval
安全ではなく、ファイル名に特定の文字が含まれている場合、任意の、場合によっては有害なコードが実行される可能性があります。バッシュ FAQ 48詳細については。
パスを引数として渡す方が良いでしょう:
#!/usr/bin/env bash
find "$@" -name "file*"
find
別のアプローチとしては、これを完全に避けて、bash の拡張グロブ機能と glob を使用することです。
#!/usr/bin/env bash
shopt -s globstar
for file in te*/my\ files/**; do echo "$file"; done
bashオプションを使用すると、再帰的に一致させるglobstar
ことができます。**
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.
ドットファイル(隠しファイル)を検索して含めるのとまったく同じように動作させるには、
#!/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 自体にこれができるはずだと気づきました。次のようになります:
find . -path 'D*/my folder/more/'
答え3
今では少し古くなっていますが、この質問の回答に役立つのであれば、 find コマンドライン引数内で変数を[[.space.]]
引用符で囲まずにRE の照合シンボルを使用する$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
行を短くするには、 を または[.hyphen.]
に置き換え 、 を またはに置き換えることができることに注意してください。[.-.]
-
[.underscore.]
[._.]
_
\
読みやすくするために、バックスラッシュ ( ) で行を切り捨てています。
答え4
ついに答えを見つけました。
すべてのスペースにバックスラッシュを追加します。
SEARCH='te*/my files/more'
SEARCH=${SEARCH// /\\ }
この時点で、SEARCH
が含まれていますte*/my\ files/more
。
次に、 を使用しますeval
。
eval find ${SEARCH} -print
とても簡単です! を使用すると、変数からのeval
解釈が回避されます。${SEARCH}