たとえば、複数の開始点を持つディレクトリツリーを参照する必要がありますが、次のようにこれらのfind ./User1 ./User2 ./User3
開始点に存在する特定のディレクトリ名のみを処理する必要があります。./User1/Documents
./User1/Pictures
/.User2/Documents
スキップしたいそして prune
指定されたすべてのソースリストにないその他のサブフォルダ。
-not
prune
andと&\(
のさまざまな組み合わせを使用したすべての試みは\)
失敗しました。
開始点は、実行時にスクリプトによって決定されます。最後の手段としてUser?
リストを繰り返して、より大きな開始点リスト(必要なディレクトリ名が追加されました)を作成して開始点リストを構築することができました。
除外する./User?/NotInList
必要がありますが、除外することも./User?/InList/NotInList
できます。
[すべての状況:データ復旧を実行しており、Users
Microsoft Windowsフォルダの「重要」ファイルを列挙したいと思います。フォルダをPublic
スキップしDefault
(したがって、コマンドの開始点として残りのフォルダ文字列を作成しましたfind
)、Pictures
Documents
各ユーザーのetc。フォルダを選択/ドロップする代わりに、各ユーザーのAppData
etc。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
単一の配列拡張に対してこの構文が有効になります$^array
。rcexpandparam
ここに引用はrc
少し誤解を招く。 /(ここでは(1 2))はこのように拡張されていますが$array^string
(これがrcと同様のタイプの拡張がで選択された理由です)、配列を一緒に接続するのには機能しません。 In(同じ)は同じサイズの配列でのみ機能し、要素を1つずつ連結します( goes 、 is not )。rc
es
array
{1,2}string
zsh
^
$^array
rc
$array1^$arrat2
$array1$array2
(1 2)^(a b)
1a 2b
1a 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/y
x
Public
Default
y
Documents
Pictures
My Documents
extglob
Bashで有効になったら、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"