كيف يمكنني إخراج جميع الدلائل بشكل متكرر في موقع أو اتساع أولا؟

StackOverflow https://stackoverflow.com/questions/539583

  •  22-08-2019
  •  | 
  •  

سؤال

القائمة الأولية الأولى مهمة، هنا. أيضا، الحد من العمق الذي سيتم البحث فيه سيكون لطيفا.

$ find . -type d
/foo
/foo/subfoo
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub
/bar
/bar/subbar

$ find . -type d -depth
/foo/subfoo/subsub/subsubsub
/foo/subfoo/subsub
/foo/subfoo
/foo
/bar/subbar
/bar

$ < what goes here? >
/foo
/bar
/foo/subfoo
/bar/subbar
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub

أود القيام بذلك باستخدام بطانة واحدة باش، إن أمكن. إذا كانت هناك شل جافا سكريبت، فسوف أتصور شيئا مثل

bash("find . -type d").sort( function (x) x.findall(/\//g).length; )
هل كانت مفيدة؟

المحلول

ال find دعم القيادة -printf الخيار الذي يدرك الكثير من العناصر النائبة.

أحد هذا النائب هو %d الذي يجعل عمق المسار المعطى، بالنسبة إلى أين find بدأت.

لذلك يمكنك استخدام متابعة بطانة واحدة بسيطة:

find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-

انها واضحة تماما، ولا تعتمد على الأدوات الثقيلة مثل perl.

كيف تعمل:

  • يولد داخليا قائمة الملفات، حيث يتم تقديم كل خط ميدانيين
  • يحتوي الحقل الأول على عمق، يستخدم للفرز العددي (عكس)، ثم قطع
  • الناتجة هي قائمة ملفات بسيطة، ملف واحد لكل سطر، في أعماق الطلب الأول

نصائح أخرى

إذا كنت ترغب في القيام بذلك باستخدام أدوات قياسية، فيجب أن يعمل خط الأنابيب التالي:

find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2

إنه،

  1. ابحث عن وطباعة جميع الدلائل هنا في المرتبة الأولى
  2. عد عدد الخطيات في كل دليل وإعداده على المسار
  3. الترتيب حسب العمق (أي عدد سطريات)
  4. استخراج المسار فقط.

للحد من العمق الموجود، أضف الوسيطة -Maxdepth إلى أمر البحث.

إذا كنت تريد الدلائل المدرجة بنفس الترتيب الذي يجد إخراجها، استخدم "فرز -s" بدلا من "فرز -n"؛ يستقر العلم "-S" الترتيب (أي، يحافظ على ترتيب الإدخال بين العناصر التي تقارن بالتساوي).

لا أعتقد أنه يمكنك القيام بذلك باستخدام أدوات مساعدة مدمجة، حيث عند عبور التسلسل الهرمي للدليل، فأنت تريد دائما البحث عن عمق أولا، إما من أعلى إلى أسفل أو من أسفل إلى أعلى. إليك برنامج نصي Python الذي سيمنحك البحث أولا - البحث أولا:

import os, sys

rootdir = sys.argv[1]
queue = [rootdir]

while queue:
    file = queue.pop(0)
    print(file)
    if os.path.isdir(file):
        queue.extend(os.path.join(file,x) for x in os.listdir(file))

يحرر:

  1. استخدام os.path-Module بدلا من os.statوظيفي و stat-وحدة.
  2. استخدام list.pop و list.extend بدلا من del و += العاملين.

شعوري هو أن هذا هو الحل الأفضل من تلك المذكورة سابقا. أنه ينطوي على GREP وحلقة حلقة، لكنني أجد أنه يعمل بشكل جيد للغاية، على وجه التحديد للحالات التي تريد أن تكون فيها الأمور مخزنة ولا يتم العثور عليها بالكامل.

إنه أكثر كثافة من الموارد بسبب:

  • الكثير من الشوك
  • الكثير من الاكتشافات
  • يضرب كل دليل قبل العمق الحالي عن طريق العثور على عدة مرات حيث يوجد عمق إجمالي لهيكل الملف (لا ينبغي أن يكون هذا مشكلة إذا كان لديك أي كمية عمليا من ذاكرة الوصول العشوائي ...)

هذا جيد لأن:

  • يستخدم أدوات باش والغنو الأساسية
  • يمكن كسرها كلما أردت (مثلك ترى ما كنت تبحث عن الطيران)
  • إنه يعمل في كل سطر وعدم العثور عليه، لذلك لا يتعين على الأوامر اللاحقة الانتظار لإيجاد وفرز
  • إنه يعمل بناء على فصل نظام الملفات الفعلية، لذلك إذا كان لديك دليل مع اختلط فيه، فلن يتم سرده أعمق مما هو عليه؛ إذا كان لديك فاصل مسار مختلف تم تكوينه، فلن تكون بخير.
#! / صندوق بن / باش = 0 أثناء العثور على -Mindepth $ عمق -MaxDepth $ عمق | Grep ". هل العمق = $ ((عمق + 1))

يمكنك أيضا تناسبها على سطر واحد إلى حد ما (؟) بسهولة:

depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done

لكنني أفضل البرامج النصية الصغيرة عند كتابة ...

يمكنك استخدام الأمر البحث، والبحث / المسار / to / dir -type d أقل من ذلك أدناه قائمة الدلائل في الدليل الحالي:

find . -type d

حاولت أن أجد طريقة للقيام بذلك مع find ولكن لا يبدو أن لديك أي شيء مثل -breadth اختيار. اختصار كتابة التصحيح لذلك، جرب تعويذة Shell التالية (ل Bash):

LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
while test -n "$LIST"; do
    for F in $LIST; do
        echo $F;
        test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
    done;
    LIST=$NLIST;
    NLIST="";
done

أنا عنع من هذا النوع من غير قصد لذلك لا أعرف إذا كان يعمل بشكل عام (كنت اختبارها فقط على بنية الدليل المحدد الذي كنت تسأل عنه)

إذا كنت ترغب في الحد من العمق، فقم بوضع متغير عداد في الحلقة الخارجية، مثل ذلك (أنا أيضا إضافة تعليقات إلى هذه واحدة):

# initialize the list of subdirectories being processed
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
# initialize the depth counter to 0
let i=0;
# as long as there are more subdirectories to process and we haven't hit the max depth
while test "$i" -lt 2 -a -n "$LIST"; do
    # increment the depth counter
    let i++;
    # for each subdirectory in the current list
    for F in $LIST; do
        # print it
        echo $F;
        # double-check that it is indeed a directory, and if so
        # append its contents to the list for the next level
        test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
    done;
    # set the current list equal to the next level's list
    LIST=$NLIST;
    # clear the next level's list
    NLIST="";
done

(استبدل 2 في -lt 2 مع العمق)

أساسا هذا ينفذ خوارزمية البحث أولا - أول عملية البحث باستخدام $LIST و $NLIST كقائمة انتظار أسماء الدليل. إليك الطريقة الأخيرة بمثابة بطانة واحدة لسهولة النسخ واللصق:

LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; let i=0; while test "$i" -lt 2 -a -n "$LIST"; do let i++; for F in $LIST; do echo $F; test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; LIST=$NLIST; NLIST=""; done

بدون الطلب المستحق: العثور على -Maxdepth -Type D

للحصول على الطلب المستحق، عليك أن تفعل العودية بنفسك، مع هذه المصارف الصغيرة:

#!/bin/bash
r () 
{
    let level=$3+1
    if [ $level -gt $4 ]; then return 0; fi
    cd "$1"
    for d in *; do
        if [ -d "$d" ]; then
            echo $2/$d
        fi;
    done
    for d in *; do
        if [ -d "$d" ]; then
            (r "$d" "$2/$d" $level $4)
        fi;
    done
}
r "$1" "$1" 0 "$2"

ثم يمكنك استدعاء هذا البرنامج النصي مع دليل الأساس المعلمات والعمق.

إليك طريقة ممكنة، باستخدام Find. لم أختبرها جيدا، لذلك احذر المستخدم ...

depth=0
output=$(find . -mindepth $depth -maxdepth $depth -type d | sort); 
until [[ ${#output} -eq 0 ]]; do 
  echo "$output"
  let depth=$depth+1
  output=$(find . -mindepth $depth -maxdepth $depth -type d | sort)
done

شيء من هذا القبيل:

find . -type d | 
  perl -lne'push @_, $_;
    print join $/,
      sort { 
        length $a <=> length $b || 
          $a cmp $b 
        } @_ if eof'
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top