কোনও ইউনিক্স / লিনাক্স শেলের সাথে প্যাটার্ন মিললে আমি কীভাবে বিপরীত বা নেতিবাচক ওয়াইল্ডকার্ড ব্যবহার করতে পারি?


325

বলুন যে ফাইল এবং ফোল্ডারগুলি বাদ দিয়ে যাদের ডিরেক্টরিতে 'সংগীত' শব্দটি রয়েছে সেগুলি বাদ দিয়ে আমি কোনও ডিরেক্টরি সামগ্রীর অনুলিপি করতে চাই।

cp [exclude-matches] *Music* /target_directory

এটি সম্পাদন করার জন্য [বাদ-ম্যাচগুলির] জায়গায় কোথায় যাওয়া উচিত?

উত্তর:


374

ব্যাশ আপনি এটা সক্ষম করে কি করতে পারেন 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

আপনি পরে এক্সটগ্লোব অক্ষম করতে পারেন

shopt -u extglob

14
আমি এই বৈশিষ্ট্যটি পছন্দ করি:ls /dir/*/!(base*)
এরিক রবার্টসন

6
আপনি কীভাবে সমস্ত কিছু অন্তর্ভুক্ত করবেন ( ) এবং এছাড়াও বাদ দিন (খ )?
এলিজা লিন

4
আপনি কীভাবে মিলবেন, বলুন, সবকিছু fবাদ দিয়ে foo?
নলডোরিন

8
কেন এটি ডিফল্টরূপে অক্ষম?
weberc2

3
শপ্ট-ও-হিস্টিপেক্স্যান্ড যদি আপনাকে সেগুলির মধ্যে বিস্ময়কর পয়েন্টগুলির সাথে ফাইলগুলি সন্ধান করার প্রয়োজন হয় - ডিফল্টরূপে, এক্সটগ্লোব ডিফল্টরূপে বন্ধ থাকে যাতে এটি হিস্টিপেক্সান্ডের সাথে হস্তক্ষেপ না করে, দস্তাবেজে এটি ব্যাখ্যা করেছে যে এটি কেন এমন। foo ছাড়া f এর সাথে শুরু হওয়া সমস্ত কিছু মেলে: f! (oo) অবশ্যই 'খাবার' এখনও মিলবে (আপনার f দরকার হবে! (ওও *) 'foo' থেকে শুরু হওয়া জিনিসগুলি থামাতে বা আপনি মুক্তি পেতে চাইলে '.ফু' ব্যবহারে শেষ হওয়া কিছু জিনিস! ( .ফু), বা উপসর্গযুক্ত: মাইরিফিক্স! ( .ফু) (মাইপ্রিফিক্স বিএলএইচ-এর সাথে মেলে তবে মাইপ্রিফিক্স বিএলএইচ.ফু নয়)
ওসিরিসগোথ্রা

227

extglobশেল বিকল্পটি কমান্ড লাইনে আরো শক্তিশালী প্যাটার্ন ম্যাচিং দেয়।

আপনি এটি চালু করুন shopt -s extglobএবং এটি দিয়ে বন্ধ করুন shopt -u extglob

আপনার উদাহরণে, আপনি প্রাথমিকভাবে এটি করতে হবে:

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

পূর্ণ প্রাপ্তিসাধ্য EXT শেষ হয়েছে উল্লিখিত glob Bing অপারেটার (থেকে উদ্ধৃতাংশ হয় man bash):

এক্সটগ্লোব শেল বিকল্পটি শপ্ট বিল্টিন ব্যবহার করে সক্ষম করা থাকলে, বেশ কয়েকটি বর্ধিত প্যাটার্ন মেলানো অপারেটরগুলি স্বীকৃত। একটি প্যাটার্ন-তালিকা হ'ল একটি দ্বারা বিচ্ছিন্ন এক বা একাধিক নিদর্শনগুলির একটি তালিকা। নিম্নলিখিত এক বা একাধিক উপ-নিদর্শন ব্যবহার করে যৌগিক নিদর্শনগুলি গঠিত হতে পারে:

  • ? (প্যাটার্ন-তালিকা)
    প্রদত্ত নিদর্শনগুলির শূন্য বা একটি ঘটনার সাথে মেলে
  • * (প্যাটার্ন-তালিকা)
    প্রদত্ত নিদর্শনগুলির শূন্য বা তার বেশি সংখ্যার সাথে মেলে
  • + (প্যাটার্ন-তালিকা)
    প্রদত্ত নিদর্শনগুলির এক বা একাধিক ঘটনার সাথে মেলে
  • @ (প্যাটার্ন-তালিকা)
    প্রদত্ত নিদর্শনগুলির মধ্যে একটির সাথে মেলে
  • ! (প্যাটার্ন-তালিকা)
    প্রদত্ত নিদর্শনগুলির ব্যতীত অন্য কোনও কিছুর সাথে মেলে

সুতরাং, উদাহরণস্বরূপ, আপনি যদি বর্তমান ডিরেক্টরিতে থাকা ফাইল .cবা .hফাইল নয় এমন সমস্ত ফাইল তালিকাভুক্ত করতে চান তবে আপনি তা করতে পারেন:

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

অবশ্যই, সাধারণ শেল গ্লোবিং কাজ করে, তাই শেষ উদাহরণটিও এটি হিসাবে লেখা যেতে পারে:

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

1
-ডির কারণ কী?
বড় ম্যাকলার্জহিউজ

2
@ কোভেরাস যে ক্ষেত্রে .cবা .hফাইলগুলির মধ্যে একটি ডিরেক্টরি হয় সেটির জন্য ।
tzot

@ ডেভ কেনেডি এটি বর্তমান ডিরেক্টরিতে সমস্ত কিছু তালিকাভুক্ত করার জন্য D, তবে ডিরেক্টরিতে থাকা সাব-ডাইরেক্টরিগুলির সামগ্রী নয় D
স্পুরা

23

ব্যাশে নয় (যা আমি জানি) তবে:

cp `ls | grep -v Music` /target_directory

আমি জানি এটি ঠিক আপনি যা খুঁজছিলেন তা নয়, তবে এটি আপনার উদাহরণ সমাধান করবে।


ডিফল্ট ls প্রতি লাইনে একাধিক ফাইল রাখবে, যা সম্ভবত সঠিক ফলাফল দেয় না।
ড্যানিয়েল বাঙ্গার্ট

10
শুধুমাত্র যখন স্টডআউট একটি টার্মিনাল। যখন পাইপলাইনে ব্যবহৃত হয়, ls প্রতি লাইনে একটি ফাইলের নাম মুদ্রণ করে।
অ্যাডাম রোজনফিল্ড 21

টার্মিনালে আউটপুট হলে ls কেবল প্রতি লাইনে একাধিক ফাইল রাখে। এটি নিজে চেষ্টা করে দেখুন - "ls | কম" -এর প্রতি লাইনে কখনও একাধিক ফাইল থাকবে না।
চামচমাইজার 21

3
এটি ফাঁকা স্থান (বা অন্যান্য সাদা স্পেসেস অক্ষর) সহ ফাইলের নামের জন্য কাজ করবে না।
tzot

7

আপনি যদি এক্সিকিউটিভ কমান্ডটি ব্যবহারের স্মৃতিচারণা এড়াতে চান তবে আমি বিশ্বাস করি যে আপনি 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/

6

ব্যাশ সালে বিকল্প shopt -s extglobনেই GLOBIGNOREপরিবর্তনশীল । এটি আসলে ভাল নয়, তবে মনে রাখা এটি আমার পক্ষে সহজ।

একটি উদাহরণ যা মূল পোস্টারটি চেয়েছিল তা হতে পারে:

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

হয়ে গেলে সোর্স ডিরেক্টরিতে unset GLOBIGNOREসক্ষম হতে rm *techno*


5

আপনি খুব সহজ forলুপ ব্যবহার করতে পারেন :

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

1
এটি একটি পুনরাবৃত্তির সন্ধান করে যা ওপি যা চায় তার চেয়ে আলাদা আচরণ।
অ্যাডাম রোজেনফিল্ড

1
-maxdepth 1অ recursive জন্য ব্যবহার করবেন?
avtomaton

আমি শেল বিকল্পগুলি সক্ষম / অক্ষম না করেই এটি সবচেয়ে পরিষ্কার সমাধান হিসাবে পেয়েছি। ওপেন দ্বারা প্রয়োজনীয় ফলাফল পাওয়ার জন্য এই পোস্টে -ম্যাক্সডেপথ বিকল্পটি সুপারিশ করা হবে তবে এটি আপনি কী অর্জন করতে চাইছেন তার উপর নির্ভর করে।
ডেভিড Lapointe

findব্যাকটিক্স ব্যবহার করা অপ্রীতিকর উপায়ে ভেঙে যায় যদি এটি কোনও অকার্যকর ফাইলের নাম খুঁজে পায়।
ট্রিপলি

5

আমার ব্যক্তিগত পছন্দটি হ'ল গ্রেপ এবং সময় কমান্ডটি ব্যবহার করা। এটি একটিকে শক্তিশালী এখনও পঠনযোগ্য স্ক্রিপ্টগুলি লেখার অনুমতি দেয় যাতে আপনি যা চান ঠিক তেমনই শেষ করেন doing এছাড়াও ইকো কমান্ড ব্যবহার করে আপনি প্রকৃত ক্রিয়াকলাপ চালানোর আগে একটি শুকনো রান সঞ্চালন করতে পারেন। উদাহরণ স্বরূপ:

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

আপনার অনুলিপি করা ফাইলগুলি মুদ্রণ করবে। তালিকাটি সঠিক হলে পরবর্তী পদক্ষেপটি হ'ল ইকো কমান্ডটি অনুলিপি করে নিম্নরূপ:

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

1
এটি যতক্ষণ কাজ করবে আপনার ফাইলের নামগুলিতে কোনও ট্যাব, নতুনলাইন, একাধারে একাধিক স্পেস বা কোনও ব্যাকস্ল্যাশ নেই। যদিও এটি প্যাথলজিকাল কেস, তবে সম্ভাবনা সম্পর্কে সচেতন হওয়া ভাল। ইন bashআপনি ব্যবহার করতে পারেন while IFS='' read -r filename, কিন্তু তারপর নতুন লাইন এখনও কোন সমস্যা আছে। সাধারণভাবে lsফাইলগুলি গণনার জন্য ব্যবহার না করা ভাল ; মত সরঞ্জাম findঅনেক ভাল উপযুক্ত।
থার্ডওয়ার্ড

কোনও অতিরিক্ত সরঞ্জাম ছাড়াই:for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
থার্ডওয়ার্ড

mywiki.wooledge.org/ পার্সিংএলগুলি আপনাকে এড়ানো উচিত কেন এমন অনেকগুলি অতিরিক্ত কারণের তালিকা দেয়।
ট্রিপলি

5

একটি কৌতুক আমি এখানে এখনো দেখা যায় না যে ব্যবহার করে না 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)

সম্ভাব্য কার্যকর।


1
বাদ দেওয়ার সুবিধাগুলির মধ্যে একটি হ'ল ডিরেক্টরিটি প্রথম স্থানে না যাওয়া। এই সমাধানটি উপ-ডিরেক্টরিগুলির দুটি ট্র্যাভারসাল করে - একটিকে বাদ দিয়ে এবং একটি ছাড়াই।
মার্ক স্টসবার্গ

খুব ভাল পয়েন্ট, @ মার্কস্টোসবার্গ। যদিও, এই কৌশলটির একটি সুবিধা হ'ল আপনি একটি আসল ফাইল থেকে বাদ পড়তে পারেন, যেমনcomm -23 <(ls) exclude_these.list
জেমস এম। লে।

3

এর জন্য একটি সমাধান খুঁজে পাওয়া যাবে।

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

ফাইন্ডে বেশ কয়েকটি অপশন রয়েছে, আপনি কী অন্তর্ভুক্ত করবেন এবং বাদ দেবেন সে সম্পর্কে আপনি বেশ সুনির্দিষ্টভাবে জানতে পারেন।

সম্পাদনা করুন: মন্তব্যগুলিতে অ্যাডাম উল্লেখ করেছেন যে এটি পুনরাবৃত্ত। অপশনগুলি মাইন্ডপথ এবং ম্যাক্সডেপথ এটি নিয়ন্ত্রণে কার্যকর হতে পারে find


এটি একটি পুনরাবৃত্তির অনুলিপি করে যা ভিন্ন আচরণ। এটি প্রতিটি ফাইলের জন্য একটি নতুন প্রক্রিয়া তৈরি করে, যা বিপুল সংখ্যক ফাইলের জন্য খুব অদক্ষ হতে পারে।
অ্যাডাম রোজনফিল্ড 21

প্রতিটি ফাইলের অনুলিপি তৈরি করা সমস্ত আইওয়ের তুলনায় একটি প্রক্রিয়া তৈরির ব্যয় প্রায় শূন্য। তাই আমি বলতাম এটি মাঝে মধ্যে ব্যবহারের জন্য যথেষ্ট ভাল।
dland 21

প্রক্রিয়া ডিম ছাড়ার জন্য কিছু সমাধান নীচে উপস্থিত: stackoverflow.com/questions/186099/...
Vinko Vrsalovic

পুনরাবৃত্তি এড়ানোর জন্য "-maxdepth 1" ব্যবহার করুন।
এজগোটল

শেল ওয়াইল্ড কার্ডের সম্প্রসারণের অ্যানালগ পেতে ব্যাকটিক্স ব্যবহার করুন: সিপি find -maxdepth 1 -not -name '*Music*'/ টার্গেট_ডাইরেক্টরি
এজগটল

2

নীচের কাজগুলি *.txtএকটি সংখ্যা দিয়ে শুরু হওয়া ফাইলগুলি বাদ দিয়ে বর্তমান দিরের সমস্ত ফাইলের তালিকা করে ।

এই কাজ করে 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##*/}এক্সপ্রেশনটি ফাইলের নাম (এখানে /some/dir/) থেকে যে কোনও নেতৃস্থানীয় দির নাম উপাদানকে সরিয়ে দেয় যাতে প্যাটারগুলি কেবল ফাইলের বেসনামের সাথে মেলে। (যদি আপনি প্রত্যয়গুলির উপর ভিত্তি করে কেবল ফাইলের নামগুলি ঝাঁকিয়ে থাকেন তবে আপনি এটির $FILEপরিবর্তে এটি সংক্ষিপ্ত করতে পারেন ))

  3. তিন লাইনে, caseপ্যাটার্নের সাথে মেলে সমস্ত ফাইল [0-9]*) লাইন ছেড়ে দেওয়া হবে ( continueবিবৃতিটি লুপটির পরবর্তী পুনরাবৃত্তিতে forপৌঁছায়)। - আপনি চাইলে এখানে আরও কিছু আকর্ষণীয় কাজ করতে পারেন, যেমন চিঠি দিয়ে শুরু না হওয়া সমস্ত ফাইলগুলি এড়িয়ে যাওয়া (a – z) [!a-z]*, অথবা আপনি বিভিন্ন ধরণের ফাইলের নাম এড়াতে একাধিক নিদর্শন ব্যবহার করতে পারেন যেমন [0-9]*|*.bakউভয় .bakফাইল এড়িয়ে যেতে , এবং ফাইলগুলি যা কোনও সংখ্যার সাথে শুরু হয় না।


ডোহ! একটি বাগ ছিল (আমি ন্যায়বিচারের *.txtপরিবর্তে এর সাথে মেলে *)। এখনই স্থির।
zrajm

0

এটি ঠিক 'সংগীত' বাদ দিয়ে এটি করবে

cp -a ^'Music' /target

এটি এবং এটি সঙ্গীত? * বা *? সংগীতের মতো জিনিস বাদ দেওয়ার জন্য

cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target

cpMacOS এ ম্যানুয়াল পৃষ্ঠায় একটি -aবিকল্প রয়েছে তবে এটি সম্পূর্ণ আলাদা কিছু করে। কোন প্ল্যাটফর্ম এটিকে সমর্থন করে?
ট্রিপলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.