كيف يمكنني استخدام عكسية أو سلبية البدل عند مطابقة النمط في يونكس/لينكس قذيفة ؟

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

سؤال

أقول كنت تريد نسخ محتويات الدليل باستثناء الملفات و المجلدات ذات الأسماء التي تحتوي على كلمة "الموسيقى".

cp [exclude-matches] *Music* /target_directory

ما يجب أن تذهب في مكان [يستبعد-المباريات] لإنجاز هذا ؟

هل كانت مفيدة؟

المحلول

في باش يمكنك أن تفعل ذلك من خلال تمكين خيار extglob، مثل هذا (استبدال ls مع cp وإضافة الدليل الهدف، بالطبع)

~/foobar> shopt extglob
extglob        off
~/foobar> ls
abar  afoo  bbar  bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob  # Enables extglob
~/foobar> ls !(b*)
abar  afoo
~/foobar> ls !(a*)
bbar  bfoo
~/foobar> ls !(*foo)
abar  bbar

ويمكنك فيما بعد تعطيل extglob مع

shopt -u extglob

نصائح أخرى

على extglob شل الخيار يتيح لك أكثر قوة نمط مطابقة في سطر الأوامر.

تشغيله مع shopt -s extglob, و إيقاف تشغيله مع shopt -u extglob.

في المثال الخاص بك ، يمكنك أن تفعل في البداية:

$ shopt -s extglob
$ cp !(*Music*) /target_directory

الكامل المتاحة تحويلةانتهت غلوببنج مشغلي (مقتطفات من man bash):

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

  • ?(نمط القائمة)
    مباريات صفر أو واحد حدوث أنماط معينة
  • *(نمط القائمة)
    مباريات صفر أو أكثر من أنماط معينة
  • +(نمط القائمة)
    مباريات تواجد واحد أو أكثر من أنماط معينة
  • @(نمط القائمة)
    يطابق أحد أنماط معينة
  • !(نمط القائمة)
    يطابق أي شيء ما عدا واحدة من أنماط معينة

لذا, فعلى سبيل المثال, إذا أردت سرد كافة الملفات في الدليل الحالي التي لا .c أو .h ملفات, يمكنك أن تفعل:

$ ls -d !(*@(.c|.h))

طبعا عادي شل globing يعمل حتى آخر على سبيل المثال يمكن أيضا أن تكون مكتوبة على النحو التالي:

$ ls -d !(*.[ch])

وليس في باش (أن أعرف)، ولكن:

cp `ls | grep -v Music` /target_directory

وأنا أعلم أن هذا ليس بالضبط ما كنت أبحث عنه، لكنه لن يحل المثال الخاص بك.

إذا كنت ترغب في تجنب تكلفة ذاكرة من استخدام الأمر إكسيك، وأعتقد أنك يمكن أن نفعل ما هو أفضل مع xargs. وأعتقد أن ما يلي هو بديل أكثر فعالية ل

find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec



find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/

في باش بديل shopt -s extglob هو GLOBIGNORE متغير.انها ليست حقا أفضل, ولكن أجد أنه من الأسهل أن نتذكر.

مثال على ذلك قد يكون ما الملصق الأصلي أراد:

GLOBIGNORE="*techno*"; cp *Music* /only_good_music/

عندما تنتهي من ذلك ، unset GLOBIGNORE أن تكون قادرة على rm *techno* في الدليل المصدر.

ويمكنك أيضا استخدام for بسيطة جدا حلقة:

for f in `find . -not -name "*Music*"`
do
    cp $f /target/dir
done

وبلدي تفضيل شخصي هو استخدام البقرى والأمر بعض الوقت. هذا يسمح احد لكتابة البرامج النصية قوية بعد قراءة ضمان أن ينتهي بك الأمر تفعل بالضبط ما تريد. بالإضافة باستخدام الأمر echo يمكنك إجراء تجف قبل تنفيذ العملية الفعلية. على سبيل المثال:

ls | grep -v "Music" | while read filename
do
echo $filename
done

وسوف طباعة الملفات التي سوف ينتهي النسخ. إذا كانت القائمة الصحيحة الخطوة التالية هي ببساطة استبدال الأمر echo مع الأمر copy كما يلي:

ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done

ويمكن العثور على حل واحد لهذا مع البحث.

$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt

وبحث له عدد غير قليل من الخيارات، يمكنك الحصول محددة جدا على ما قمت بتضمين واستبعاد.

وتحرير: أشار آدم في التعليقات أن هذا هو العودية. العثور على خيارات mindepth وmaxdepth يمكن أن تكون مفيدة في السيطرة على هذا.

وخدعة أنا لم أر هنا بعد أن لا تستخدم extglob، find، أو grep هي لعلاج قائمتين الملف كما مجموعات و<م> "فرق" لهم باستخدام comm:

comm -23 <(ls) <(ls *Music*)

وcomm هو الأفضل على diff لأنه لم يكن لديك العناصر غير المرغوب فيها اضافية.

وهذا ما يعيد جميع عناصر مجموعة 1، ls، التي هي <م> لا أيضا في مجموعة 2، ls *Music*. وهذا يتطلب أن تكون مجموعات من أجل فرزها للعمل بشكل صحيح. لا مشكلة بالنسبة ls وغلوب التوسع، ولكن إذا كنت تستخدم شيئا مثل find، ومن المؤكد أن استدعاء sort.

comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)

ومفيدة محتملة.

الأعمال التالية يسرد كافة *.txt الملفات في التيار dir باستثناء تلك التي تبدأ مع عدد.

هذا يعمل في bash, dash, zsh وسائر POSIX متوافق قذائف.

for FILE in /some/dir/*.txt; do    # for each *.txt file
    case "${FILE##*/}" in          #   if file basename...
        [0-9]*) continue ;;        #   starts with digit: skip
    esac
    ## otherwise, do stuff with $FILE here
done
  1. في خط واحد نمط /some/dir/*.txt سوف يسبب for حلقة تكرار عبر كل الملفات في /some/dir اسمه ينتهي .txt.

  2. في الخط الثاني بيان حالة يستخدم للتخلص من الملفات غير المرغوب فيها. ـ ${FILE##*/} التعبير شرائط قبالة أي الرائدة dir اسم مكون من اسم الملف (هنا /some/dir/) بحيث أنماط يمكن أن مباراة ضد basename من الملف.(إذا كنت فقط استئصال أسماء على أساس اللواحق ، يمكنك تقصير هذا $FILE بدلا من ذلك.)

  3. في السطر الثالث, جميع الملفات مطابقة case نمط [0-9]*) خط سيتم تخطي (تم continue بيان يقفز إلى التكرار التالي من for حلقة).– إذا كنت تريد يمكنك أن تفعل شيئا أكثر إثارة للاهتمام هنا, على سبيل المثالمثل تخطي جميع الملفات التي لا تبدأ بحرف (a–z) باستخدام [!a-z]*, أو يمكنك استخدام أنماط متعددة تخطي عدة أنواع من الملفات مثل [0-9]*|*.bak إلى تخطي الملفات على حد سواء .bak والملفات التي لا تبدأ برقم.

وهذا من شأنه أن تفعل ذلك باستثناء بالضبط "الموسيقى"

cp -a ^'Music' /target

وهذا وذاك لاستبعاد الأشياء مثل الموسيقى؟ * أو *؟ الموسيقى

cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top