linux commands




كيفية استبعاد دليل في البحث. أمر (20)

أجد ما يلي أسهل في التفكير حول الحلول المقترحة الأخرى:

find build -not \( -path build/external -prune \) -name \*.js

يأتي هذا من حالة استخدام فعلية ، حيث أحتاج إلى استدعاء yui-compressor على بعض الملفات التي تم إنشاؤها بواسطة wintersmith ، ولكن اترك الملفات الأخرى التي تحتاج إلى إرسالها كما هي.

Inside \( و \) هو تعبير يتطابق تمامًا مع البنية build/external ، وسيتجنب ، عند النجاح ، عبور أي شيء أدناه . ثم يتم تجميعها كتعبير واحد مع الأقواس المنبثقة ، وتبدأ بـ -not والذي سيجعل find تخطي أي شيء تم مطابقته بواسطة هذا التعبير.

قد يتساءل المرء إن كانت إضافة -not لن تجعل جميع الملفات الأخرى مخفية من قبل -prune ، والرد هو لا. طريقة العمل - -prune هو أن أي شيء ، بمجرد الوصول إليه ، يتم تجاهل الملفات الموجودة أسفل هذا الدليل بشكل دائم.

من السهل أيضًا التوسع لإضافة استبعادات إضافية. فمثلا:

find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

أحاول تشغيل أمر بحث لجميع ملفات جافا سكريبت ، ولكن كيف أستبعد دليلًا محددًا؟

إليك شفرة التعرّف التي نستخدمها.

for file in $(find . -name '*.js'); do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file; done

أردت أن أعرف عدد الدلائل ، ملفات MB فقط من الدليل الحالي - وهذا الرمز يفعل بالضبط ما أريد :-)

المصدر

- ...    2791037 Jun  2  2011 foo.jpg
- ... 1284734651 Mär 10 16:16 foo.tar.gz
- ...          0 Mär 10 15:28 foo.txt
d ...       4096 Mär  3 17:12 HE
d ...       4096 Mär  3 17:21 KU
d ...       4096 Mär  3 17:17 LE
d ...          0 Mär  3 17:14 NO
d ...          0 Mär  3 17:15 SE
d ...          0 Mär  3 17:13 SP
d ...          0 Mär  3 17:14 TE
d ...          0 Mär  3 19:20 UN

الرمز

format="%s%'12d\n"

find . -type d -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Ordner  = ", $1-1}'
find . -type f -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Dateien = ", $1}'
  du . -hmS --max-depth=0 | awk -v fmt=$format '{printf fmt, " Groesse (MB)   = ", $1}'

ملاحظة: format="%s%'12d\n" الإضافي format="%s%'12d\n" ضروري لـ awk لتنسيق الأرقام.

النتائج

Anzahl Ordner  =            8
Anzahl Dateien =            3
Groesse (MB)   =        1.228

أفضّل -not notation ... إنه أكثر قابلية للقراءة:

find . -name '*.js' -and -not -path directory

إذا كان لديك أدلة البحث نمط (في حالتي في معظم الأحيان) ؛ يمكنك ببساطة القيام بذلك مثل أدناه:

find ./n* -name "*.tcl" 

في المثال أعلاه يقوم بالبحث في جميع الدلائل الفرعية التي تبدأ بـ "n".


استخدم خيار -Bune. إذن ، شيء من هذا القبيل:

find . -type d -name proc -prune -o -name '*.js'

يبحث "-pepe d -name proc -prune" فقط عن الدلائل المسماة proc لاستبعادها.
"-o" هو عامل تشغيل "OR".


استخدم مفتاح التبديل ، على سبيل المثال إذا كنت ترغب في استبعاد دليل misc فقط قم بإضافة -path ./misc -prune -o إلى الأمر find الخاص بك:

find . -path ./misc -prune -o -name '*.txt' -print

إليك مثال مع دلائل متعددة:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

هنا نستثني dir1 ، dir2 و dir3 ، لأن find عن تعبيرات هو إجراء ، يعمل على المعايير -path dir1 -o -path dir2 -o -path dir3 (إذا dir1 أو dir2 أو dir3) ، ANDed مع type -d . مزيد من العمل هو -o print ، فقط طباعة.


تعمل طريقة -path -prune أيضًا مع أحرف البدل في المسار. في ما يلي عبارة بحث ستعثر على الأدلة الخاصة بخادم git الذي يقدم عدة مستودعات git تاركة الأدلة الداخلية git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  

جربت الأمر أعلاه ، لكن لا أحد من أولئك الذين يستخدمون "-المال" يعمل معي. في النهاية حاولت ذلك باستخدام الأمر أدناه:

find . \( -name "*" \) -prune -a ! -name "directory"

كنت أستخدم find لتوفير قائمة من الملفات ل xgettext ، وأردت حذف دليل محدد ومحتوياته. لقد جربت العديد من التباديل من -prune جنبا إلى جنب مع -prune ولكن لم يكن قادراً على استبعاد الدليل الذي تريده بالكامل.

على الرغم من أنني تمكنت من تجاهل محتويات الدليل التي أردت تجاهلها ، find ثم أرجعت الدليل نفسه كواحدة من النتائج ، مما أدى إلى تعطل xgettext كنتيجة (لا يقبل الدلائل ؛ فقط الملفات).

كان الحل grep -v استخدام grep -v لتخطي الدليل الذي لم أكن أريده في النتائج:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

سواء كان هناك حجة find أن تعمل بنسبة 100٪ ، لا أستطيع أن أقول على وجه اليقين. استخدام grep كان حل سريع وسهل بعد بعض الصداع.


لأولئك منكم على الإصدارات القديمة من UNIX الذين لا يمكنهم استخدام -path أو -not

اختبارها على SunOS 5.10 bash 3.2 و SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f

لاستبعاد دلائل متعددة:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

لإضافة أدلة ، أضف -o -path "./dirname/*" :

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

ولكن ربما يجب عليك استخدام تعبير عادي ، إذا كان هناك العديد من الأدلة لاستبعادها.


لقد وجدت أن اسم الوظائف في ملفات مصادر C استبعاد * .o واستبعاد * .swp واستبعاد (ليس الملف العادي) واستبعاد الإخراج dir باستخدام هذا الأمر:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach

للحصول على حل عملي (تم اختباره على Ubuntu 12.04 (Pangolin Precise)) ...

find ! -path "dir1" -iname "*.mp3"

سيبحث عن ملفات MP3 في المجلد الحالي والمجلدات الفرعية باستثناء المجلد الفرعي dir1.

استعمال:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... لاستبعاد dir1 و dir2


من الواضح أن هناك بعض الارتباك هنا حول ما يجب أن يكون عليه بناء الجملة المفضل لتخطي الدليل.

جنو الرأي

To ignore a directory and the files under it, use -prune

من غنو تجد صفحة رجل

منطق

-prune توقف find من تنازلي إلى دليل. سيظل تحديد فقط -not -path ينزل إلى الدليل الذي تم تخطيه ، لكن -not -path سيكون خطأ عند find كل ملف.

القضايا مع -prune

-prune ما يفعله ، ولكن لا تزال هناك بعض الأشياء التي يجب عليك الاعتناء بها عند استخدامه.

  1. find طباعة الدليل المشذب.

    • TRUE هذا هو السلوك المقصود ، فهو لا ينزل إليه. لتجنب طباعة الدليل تمامًا ، استخدم بناء جملة يحذفه منطقيًا.
  2. -prune يعمل فقط مع -print وأي إجراءات أخرى.

    • ليس صحيح . يعمل مع أي عمل باستثناء -delete . لماذا لا تعمل مع الحذف؟ للحصول على العمل ، ابحث عن احتياجات لاجتياز الدليل في ترتيب DFS ، حيث أن -delete سيحذف الأوراق أولاً ، ثم الآباء من الأوراق ، الخ ... ولكن لتحديد -prune ، find احتياجات لتصل إلى الدليل والتوقف عن -delete عنها ، والتي من الواضح أنه لا معنى له مع -delete أو -delete .

أداء

أعددت اختبارًا بسيطًا للأجوبة الثلاثة الأعلى من الأسئلة حول هذا السؤال (استبدلت -print بـ -print -exec bash -c 'echo $0' {} \; لإظهار مثال إجراء آخر). النتائج أدناه

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

استنتاج

استغرق تركيب كل من f10bit وبناء دانيال سي سوبرال 10-25 مللي ثانية لتشغيل في المتوسط. استغرق بناء جملة GetFree ، والتي لا تستخدم -prune ، 865ms. لذا ، نعم هذا مثال متطرف ، ولكن إذا كنت تهتم بوقت التشغيل وتقوم بأي شيء عن بعد ، فيجب عليك استخدام جهاز -prune .

لاحظ أن بنية دانيال سوبرال أدت الأداء الأفضل -prune . ولكن ، أشك بشدة في أن هذه النتيجة ناتجة عن بعض التخزين المؤقت حيث أن تبديل الترتيب الذي تم تشغيل الترتيبين فيه أدى إلى النتيجة المعاكسة ، في حين كانت النسخة غير الخاطئة أبطأ دائمًا.

اختبار كتابي

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

هذا هو التنسيق الذي استخدمته لاستبعاد بعض المسارات:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

لقد استخدمت هذا للعثور على جميع الملفات غير الموجودة في المسارات ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

هذا هو الوحيد الذي عمل بالنسبة لي.

البحث عن "NameOfFile" باستثناء "الدليل". التركيز على النجوم *.

find / -name NameOfFile ! -path '*/Directory/*'

يعمل ذلك نظرًا find TESTS الملفات الخاصة بالنمط " * foo * ":

find ! -path "dir1" ! -path "dir2" -name "*foo*"

لكنه لا يعمل إذا كنت لا تستخدم نمط (لا تبحث عن اختبار الملف). لذلك ، لا يجدي "البحث" أي استخدام لمخزونه " الحقيقي " و " الباطل " الذي تم تقييمه سابقًا. مثال لحالة الاستخدام غير المستخدمة مع الملاحظة أعلاه:

find ! -path "dir1" ! -path "dir2" -type f

لا يوجد find اختبار! حتى إذا كنت بحاجة إلى العثور على الملفات دون أي تطابق نمط استخدام -الخ. أيضا ، من خلال استخدام البحث عن الخوخ هو دائما أسرع في حين أنه يتخطى حقا تلك الدلائل بدلا من مطابقة أو أفضل عدم مطابقة ذلك. في هذه الحالة ، استخدم شيئًا مثل:

find dir -not \( -path "dir1" -prune \) -not \( -path "dir2" -prune \) -type f

أو:

find dir -not \( -path "dir1" -o -path "dir2" -prune \) -type f

مع تحياتي


يمكنك استخدام خيار prune لتحقيق ذلك. كما هو الحال في على سبيل المثال:

find ./ -path ./beta/* -prune -o -iname example.com -print

أو الخيار grep -v معكوس grep:

find -iname example.com | grep -v beta

يمكنك العثور على التعليمات التفصيلية والأمثلة في أمر البحث عن Linux والتي تستبعد الدلائل من البحث .


how-to-use-prune-option-of-find-in-sh -prune how-to-use-prune-option-of-find-in-sh -prune how-to-use-prune-option-of-find-in-sh هي إجابة ممتازة من قبل لورانس غونسالفيس حول كيفية عمل -prune .

وهنا الحل العام:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

لتجنب كتابة /path/to/seach/ عدة مرات ، قم بلف find في pushd .. popd pair.

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

 find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune




find