كيف يمكنني استخدام عكسية أو سلبية البدل عند مطابقة النمط في يونكس/لينكس قذيفة ؟
-
03-07-2019 - |
سؤال
أقول كنت تريد نسخ محتويات الدليل باستثناء الملفات و المجلدات ذات الأسماء التي تحتوي على كلمة "الموسيقى".
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
في خط واحد نمط
/some/dir/*.txt
سوف يسببfor
حلقة تكرار عبر كل الملفات في/some/dir
اسمه ينتهي.txt
.في الخط الثاني بيان حالة يستخدم للتخلص من الملفات غير المرغوب فيها. ـ
${FILE##*/}
التعبير شرائط قبالة أي الرائدة dir اسم مكون من اسم الملف (هنا/some/dir/
) بحيث أنماط يمكن أن مباراة ضد basename من الملف.(إذا كنت فقط استئصال أسماء على أساس اللواحق ، يمكنك تقصير هذا$FILE
بدلا من ذلك.)في السطر الثالث, جميع الملفات مطابقة
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