findを使用してファイル名の特殊文字を処理する方法

findを使用してファイル名の特殊文字を処理する方法

次のような特定の文字で始まるすべてのファイルを見つけたいです。

find . -maxdepth 1 \( -name "^m*" -a ! -name "g$" \) -print

しかし、誰かが名前に特殊文字を含むファイルを作成した場合はどうなりますか?例えば

touch "
marst"

基準を満たしても検出されません。スペースで始まるファイルを見つけるには、コードをどのように変更する必要がありますか?

また、\( -name "^m*" -a ! -name "g$" \)findのファイルが「marr」ではなく「./marr」なので、機能しません。これは何も見つからないことを意味します。単語の先頭に一致するようにコードをどのように変更できますか?

答え1

-name常に名前だけが一致します。つまり、パスと一致しません。みんな名前。その値は正規表現ではなくパターンなので、次のようにしてm開始するファイル名を見つけることができます。

-name 'm*'

gそして次に終わる名前

-name '*g'

正規表現を使用するには、-regexオプションを参照してください。

答え2

改行文字で始まるファイルまたは次のファイル名を一致させるには、次のようにしますm

NL='
'
find . \( -name 'm*' -o -name "*${NL}m*" \) -print

少なくとも GNU の場合、find有効な*文字シーケンスを形成しないバイトシーケンスは一致しません。これが潜在的な問題であれば、Cロケールを使用する方が良いでしょう。

LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) -print

例:

$ touch mom $'two\nminutes' $'mad\x80'
$ find . -name 'm*'
./mom
$ find . \( -name 'm*' -o -name "*${NL}m*" \) -print
./two?minutes
./mom
$ LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) -print
./mad?
./two?minutes
./mom

次から始まるmが終わらない行を含むファイル名の場合g

LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) ! \(
  -name '*g' -o -name "*g${NL}*" \) -print

一部のfind実装では、ファイルマッチングのための非標準オプションがあります。(通常はそうではありません。名前)正規表現を使用しますが、実装によって動作が異なるため、ここでは必要ありません。

mたとえば、正規表現が必要な場所は、名前が終わる行で始まらないファイルを見つけることですg(例:nor$'cat\nman\ndog'ではない)。$'plate\nmug\ncup'$'cat\nman\nmug'

GNUの使用find:

LC_ALL=C find . -regextype posix-extended -regex \
  ".*/(([^m$NL/][^/$NL]*|m[^/$NL]*[^$NL/g]|m|)($NL|\$))*"

mまたは、名前が次のように始まり、終わらない行が1つ以上あるファイルg(に似てい$'mad\nmug'ませんが$'ming\nmong'):

LC_ALL=C find . -regextype posix-extended -regex \
  ".*/([^/]*$NL)?m([^$NL/]*[^g$NL/])?(\$|${NL}[^/]*)"

答え3

この-regexフラグを使用して、globが提供するより複雑な一致が必要かどうかを確認できます。フルパスと一致するため、ファイル名部分のみを一致させるには、次のようにします。

find . -maxdepth 1 -regex '/[ 
]?m[^/]*[^g]$' -print

参考にしてくださいこの回答改行文字を一致させるために使用できないため、要求したため、文字クラス\nにスペースを含む改行文字を入れます。

答え4

^findでは、theまたはtheを$単純な名前として使用する必要はありません。
用途を探すモデル名前のため。パターンは次のとおりです。

  • フルネームと一致します。最初から最後まで。いつも。
  • findは、このパターンを使用する前に見つかったすべてのファイルのパスを削除します。
  • 唯一の特殊文字は* ?and [ ](^または$ではありません)です。

mしたがって、で始まるファイルを一致させるにはいいえ次に終わりますg

 find . -maxdepth 1 -name 'm*[!g]' -o -name 'm'

'm'ファイルに文字が1つしかない場合を扱います。

ただし、作成したファイルtouch $'\nmarst'(たとえば、bashのように改行を作成できます)は、new-lineで始まるのではなく、mnew-lineで始まります$'\n'。単純モードでは置き換える方法はありませんが、-ofindのOR()オプションを使用できます。

find . -maxdepth 1 \( -name 'm*' -o -name $'\n'"m*" \) -a ! -name '*g'

要件が長くなるとこれは難しくなります。
非常に複雑な文字列の場合は、-regexfindオプションを使用できます。

関連情報