複数の剪定を含む複雑な検索コマンド

複数の剪定を含む複雑な検索コマンド

たとえば、複数の開始点を持つディレクトリツリーを参照する必要がありますが、次のようにこれらのfind ./User1 ./User2 ./User3開始点に存在する特定のディレクトリ名のみを処理する必要があります。./User1/Documents ./User1/Pictures /.User2/Documentsスキップしたいそして prune指定されたすべてのソースリストにないその他のサブフォルダ。

-notpruneandと&\(のさまざまな組み合わせを使用したすべての試みは\)失敗しました。

開始点は、実行時にスクリプトによって決定されます。最後の手段としてUser?リストを繰り返して、より大きな開始点リスト(必要なディレクトリ名が追加されました)を作成して開始点リストを構築することができました。

除外する./User?/NotInList必要がありますが、除外することも./User?/InList/NotInListできます。

[すべての状況:データ復旧を実行しており、UsersMicrosoft Windowsフォルダの「重要」ファイルを列挙したいと思います。フォルダをPublicスキップしDefault(したがって、コマンドの開始点として残りのフォルダ文字列を作成しましたfind)、Pictures Documents各ユーザーのetc。フォルダを選択/ドロップする代わりに、各ユーザーのAppDataetc。Contactsフォルダのみを選択/ドロップする必要があります。ほとんど重要ではありません。 ]

答え1

そしてzsh

users=(User1 User2)
# or users=($(<userlist.txt))
# if userlist.txt contains a list of users as separate words

dirs=(Documents Pictures ...)

find ./$^users/$^dirs

fish同じ

set users User1 User2 ...
set dirs Documents Pictures
find ./$users/$dirs

fishまたは、中zsh -o rcexpandparam括弧拡張を使用して配列を拡張します。では、zsh単一の配列拡張に対してこの構文が有効になります$^arrayrcexpandparam

ここに引用はrc少し誤解を招く。 /(ここでは(1 2))はこのように拡張されていますが$array^string(これがrcと同様のタイプの拡張がで選択された理由です)、配列を一緒に接続するのには機能しません。 In(同じ)は同じサイズの配列でのみ機能し、要素を1つずつ連結します( goes 、 is not )。rcesarray{1,2}stringzsh^$^arrayrc$array1^$arrat2$array1$array2(1 2)^(a b)1a 2b1a 1b 2a 2b

これらはそうではありません。ワイルドカード、ファイルが存在するかどうかに関係なくUser1/Documents渡されます。find実際に存在するファイルまたはディレクトリのリストを渡します。存在する、ではzshできます

find ./$^users/$^dirs(N)

このパスは、(N)この配列乗算のすべての要素の結果にglob修飾子を追加し、2つの効果があります。

  • グローバル変数で作成します。つまり、一致するファイルに展開されます。
  • globがファイルと一致しない場合(ワイルドカードがないため、0または1のみが一致します)、結果globは空の状態に拡張されます。

または、次のことができます。全体的な状況すべての方法:

find (User1|User2)/(Documents|Pictures)

またはあなたの例に基づいて:

set -o extendedglob # best in ~/.zshrc
find ./^(#i)(Default|Public)/(Documents|Pictures)

あるいは、配列に基づいてglobを作成します。

find (${(j:|:)~${(b)users}})/${(j:|:)~${(b)dirs}}

どこ:

  • (b)配列要素にワイルドカード文字がある場合は、引用符で囲みます。
  • (j:|:)彼らと参加|
  • ~拡張時にワイルドカードをオンにする

すべてのファイル名を使用できます(-制限から始まるファイル名を除くfind)。

find特にランダムなファイル名を許可したい場合は、それ自体を使用するのが非常に難しいかもしれません。しかし...)のDefaultように比較的まともな方は、Public以下を試してみることができます。

LC_ALL=C find . -name . -o -path './*/*' \( ! -path './*/*/*' \
  ! -name Documents ! -name Pictures -prune -o -print \) -o   \
  ! -name Default ! -name Public -o -prune

(この種のことは私に頭痛を与えます。)

これは、大文字と小文字を区別しない一致が必要な場合、またはGNU(あなたが使用しているようです)または互換性を使用している場合にfind使用できる標準構文を使用することです。-name '[pP][uU][bB][lL][iI][cC]'find-iname Public

答え2

あなたが直接投稿した回答を見ると、現在のディレクトリから、またはを除くすべてのディレクトリがあり、、、またはのいずれかであるディレクトリを選択しようとします。./x/yxPublicDefaultyDocumentsPicturesMy Documents

extglobBashで有効になったら、globを使用してこれを実行できます。 (kshではモードがコマンドラインに直接あるときのデフォルト値であり、Zshではを使用する必要がありますsetopt kshglob。)

一方:

$ mkdir -p {Someuser,"other user",Public,Default}/{Pictures,"My Documents",Uselessdir}

ここにあるglobはあなたが望むことをしなければなりません。

$ shopt -s extglob
$ printf "%s\n" ./!(Public|Default)/@(Documents|My Documents|Pictures)
./other user/My Documents
./other user/Pictures
./Someuser/My Documents
./Someuser/Pictures

だから、あなたは走ることができるはずです

shopt -s extglob
find ./!(Public|Default)/@(Documents|My Documents|Pictures) ...

globは存在しないディレクトリに展開されないため、ディレクトリがfind存在しない場合でもエラーは発生しません./Someuser/Pictures

shopt -s nocaseglob大文字と小文字を区別せずに一致させるには、追加してください。

答え3

bash中かっこ拡張の使用に関する@StephaneChazelasのコメントに基づいて、ファイル名のスペースを処理し、ユーザーが1人の場合など、極端なケースを処理するソリューションは次のとおりです。

中括弧の拡張に使用される文字列は変数に格納されるため、eval実際に拡張するにはその文字列を使用する必要があります。

# escape spaces with backslash
directories=Documents,Pictures,My\ Documents

# get usernames to use with expansion
# and escape any spaces using sed
user_folders=$(find . -maxdepth 1 -mindepth 1 -not -iname Public -a -not -iname Default -type d -printf "%f," | \
sed 's| |\\ |g' )   

# remove trailing comma from last user's name
user_folders=${user_folders::-1}    

# only use brace expansion if there is more than one user; if there's only
# one value it won't expand and we'll be left with braces
[[ $user_folders = *,* ]] && user_folders="{$user_folders}"

find_string="find $user_folders/{$directories}"
eval "$find_string"

関連情報