ফাইলগুলি মুছতে rm $ (ls) ব্যবহারের কোনও অসুবিধা আছে কি?


13

আমি ভাবছিলাম যে rm $(ls)ফাইলগুলি মুছতে (বা rm -r $(ls)ডিরেক্টরিগুলি মুছে ফেলার জন্য) ব্যবহার করা কি নিরাপদ ছিল? কারণ সমস্ত ওয়েবসাইটে, লোকেরা এটি করার অন্যান্য উপায় দেয় যদিও এই আদেশটি অন্যান্য আদেশের চেয়ে অনেক সহজ মনে হয়।


3
বেসিক উত্তর, না। ls বিশেষ অক্ষরগুলি পরিচালনা করতে পারে না। এটিকে আরও বিশদে ব্যাখ্যা করার জন্য আমি কিছুটা উত্তর লিখতে পারি
সের্গি কলডিয়াজহনি

5
touch 'foo -r .. bar'; rm $(ls); আমার পিতামহ ডিরেক্টরিটি কোথায় যাবে? এছাড়াও, আপনি কী ধরণের বিকল্প দেখছেন যা এর চেয়ে আরও জটিল? rm *টাইপ করা এবং এটি সম্পর্কে চিন্তা করা এবং নিরাপদ করা অনেক সহজ (তবে পুরোপুরি নিরাপদ নয়; ডেনিসের উত্তর দেখুন)।
পিটার কর্ডস

1
চমৎকার উত্তরের পাশাপাশি, সচেতন থাকুন lsযা বাস্তবায়নের মধ্যে পৃথক হতে পারে এবং তাই এটি মানক নয়। আপনার যা প্রয়োজন তার উপর নির্ভর করে findএবং এর মতো বিকল্পগুলি বিবেচনা করুন stat। আপনার lsকেবলমাত্র মানুষের ব্যবহারের জন্য ব্যবহার করা উচিত, অন্য কমান্ড বা স্ক্রিপ্টগুলিতে কখনও ব্যবহারের জন্য নয়।
ধানের ল্যান্ডাউ

উত্তর:


7

এটি করার উদ্দেশ্যে কি?

  • ls বর্তমান ডিরেক্টরিতে ফাইলগুলি তালিকাভুক্ত করে
  • $(ls)lsযুক্তি হিসাবে স্থানগুলির আউটপুট প্রতিস্থাপন করেrm
  • মূলত rm $(ls)বর্তমান ডিরেক্টরিতে সমস্ত ফাইল মোছার উদ্দেশ্যে করা হয়

এই ছবির কি সমস্যা ?

lsফাইলনামে বিশেষ অক্ষরগুলি সঠিকভাবে পরিচালনা করতে পারে না। ইউনিক্স ব্যবহারকারীদের সাধারণত বিভিন্ন পন্থা ব্যবহার করার পরামর্শ দেওয়াফাইলের নাম গণনা সম্পর্কে একটি সম্পর্কিত প্রশ্নে আমি এটিও দেখিয়েছি । এই ক্ষেত্রে:

$ touch file$'\n'name                                                                                                    
$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ 

এছাড়াও, ডেনিসের উত্তরে যথাযথভাবে উল্লিখিত হিসাবে, নেতৃস্থানীয় ড্যাশযুক্ত ফাইলের নামটি rmপ্রতিস্থাপনের পরে যুক্তি হিসাবে ব্যাখ্যা করা যেতে পারে , যা ফাইলের নাম অপসারণের উদ্দেশ্যকে পরাস্ত করে।

কি কাজ

আপনি বর্তমান ডিরেক্টরিতে ফাইলগুলি মুছতে চান। সুতরাং গ্লোব ব্যবহার করুন rm *:

$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$ 

আপনি findকমান্ড ব্যবহার করতে পারেন । এই সরঞ্জামটি প্রায়শই কেবল বর্তমান ডিরেক্টরিগুলির চেয়ে বেশি জন্য সুপারিশ করা হয় - এটি অবিচ্ছিন্নভাবে পুরো ডিরেক্টরি ট্রিকে অতিক্রম করতে পারে এবং এর মাধ্যমে ফাইলগুলিতে অপারেট করতে পারে-exec . . .{} \;

$ touch "file name"                                
$ find . -maxdepth 1 -mindepth 1                                                                                         
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;                                                                          
$ ls
$ 

পাইথন ফাইলের বিশেষ অক্ষরগুলির সাথে ইস্যু করে না, তাই আমরা এটিও নিয়োগ করতে পারি (লক্ষ্য করুন যে এটি কেবল ফাইলগুলির জন্য, আপনাকে ব্যবহার করতে হবে os.rmdir()এবং os.path.isdir()আপনি ডিরেক্টরিতে পরিচালনা করতে চান):

python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

প্রকৃতপক্ষে, উপরের কমান্ডটি ~/.bashrcসংক্ষিপ্ততার জন্য ফাংশন বা উলেস রূপান্তরিত হতে পারে । উদাহরণ স্বরূপ,

rm_stuff()
{
    # Clears all files in the current working directory
    python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

}

পার্ল সংস্করণ হবে

perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'

1
"$(ls)"ডিরেক্টরিতে কেবল একটি ফাইল থাকলে আপনার উদাহরণটি কাজ করে। আপনি কেবলমাত্র ফাইল নামটি প্রসারিত করতে ট্যাব-সমাপ্তি ব্যবহার করতে পারেন কারণ এটি একমাত্র সম্পূর্ণ।
পিটার কর্ডেস

@ পিটারকর্ডস প্রকৃতপক্ষে, অদ্ভুত কারণে এটি কেবল একটি ফাইলের সাথে কাজ করে। এটি lsতখন ব্যবহারের বিরুদ্ধে আরও একটি যুক্তি: :) আমি এটি সম্পাদনা করব
সের্গি কলডায়াজনি

আমি এটিকে একটি বিজোড় কারণ বলব না: আপনি $(ls)শব্দের বিভাজন অক্ষম করার জন্য উদ্ধৃতি দিয়েছেন, বা আপনি শব্দ বিভাজন ঘটতে দিয়েছেন (বিপর্যয়কর ফলাফল সহ)। কোড হিসাবে ডাটা হিসাবে চিকিত্সা না করে একাধিক স্ট্রিংয়ের তালিকার চারপাশে যাওয়ার একমাত্র পরিষ্কার উপায় হ'ল অ্যারে ভেরিয়েবলগুলির সাথে বা \0বিভাজক হিসাবে, তবে শেল নিজেই এটি করতে পারে না। তবুও IFS=$'\n'সবচেয়ে কম বিপজ্জনক, তবে মেলাতে পারে না find -print0 | xargs -0। বা grep -l --null। অথবা আপনি পছন্দ মতো বিষয়গুলি দিয়ে পুরো বিষয়টি এড়িয়ে যান find -exec rm {} +। ( +আরএম এর প্রতিটি অনুরোধে একাধিক আরগ পাস করার জন্য নোট করুন ; আরও দক্ষ)
পিটার কর্ডস

@ পিটারকর্ডস ইউপ, সম্পূর্ণরূপে সেখানে একমত হয়েছেন। তবে IFS=$'\n'এই ক্ষেত্রেও ব্যর্থ হবে, যেহেতু আমি ফাইলনামে নতুন লাইন করেছি তাই ওয়ার্ডস্প্লিটিং এটিকে একটির পরিবর্তে দুটি ফাইলের নাম হিসাবে বিবেচনা করবে। অদ্ভুত কারণটি হ'ল সত্য যে IFSডিফল্টর সাথে যা স্থান, ট্যাব, নিউলাইন, মূলটিও rm "$(ls)"ব্যর্থ হওয়া উচিত, এটির মতো আচরণ করা উচিত আমি ফাইলনামটিকে দুটি পৃথক হিসাবে বলেছিলাম, তবে তা হয়নি। সাধারণত আমি ব্যবহার findসঙ্গে -exec, অথবা find . . .-print0 | while IFS= read -d'' FILENAME ; do . . . doneগঠন ফাইলের নামের মোকাবেলা করতে। বা একটি ব্যবহার করতে পারে python, আমি এর উদাহরণ যোগ করেছি।
সের্গেই কলডিয়াজনি

"$(ls)"সর্বদা একটি যুক্তিতে প্রসারিত হয় কারণ $(ls)শব্দ-বিভাজন থেকে উদ্ধৃতিগুলি প্রসারণকে রক্ষা করে । ঠিক যেমন তারা রক্ষা করে "$foo"
পিটার কর্ডেস

26

না, এটি নিরাপদ নয় এবং সাধারণভাবে ব্যবহৃত বিকল্পটি rm *খুব বেশি নিরাপদ নয়।

আছে অনেক সমস্যা rm $(ls)। যেহেতু অন্যরা ইতিমধ্যে তাদের উত্তরগুলি কভার করেছে, আউটপুটটি অভ্যন্তরীণ ক্ষেত্র বিভাজকls উপস্থিত উপস্থিত অক্ষরে বিভক্ত হবে ।

সেরা ক্ষেত্রে, এটি সহজভাবে কাজ করে না। সবচেয়ে খারাপ পরিস্থিতি, আপনি কেবল ফাইলগুলি (ডিরেক্টরিগুলি নয়) মুছে ফেলতে চেয়েছিলেন - বা বেছে বেছে কয়েকটি ফাইল মুছে ফেলতে -iচেয়েছিলেন - তবে c -rfবর্তমান ডিরেক্টরিতে নামের একটি ফাইল রয়েছে । চল দেখি কি ঘটলো.

$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf

কমান্ডটি rm -i $(ls)কেবলমাত্র ফাইলগুলি মুছে ফেলার এবং প্রতিটি অপসারণের পূর্বে জিজ্ঞাসা করার কথা ছিল, তবে শেষ অবধি কার্যকর করা আদেশটি পড়তে পেত

rm -i a b c -rf

সুতরাং এটি পুরোপুরি অন্য কিছু করেছিল।

মনে রাখবেন যে rm *কেবলমাত্র সামান্য ভাল। ডিরেক্টরি কাঠামোটি আগের মতোই এটি এখানে যেমন ইচ্ছা তেমন আচরণ করবে তবে আপনার যদি একটি ফাইল বলা হয় তবে -rfআপনি এখনও ভাগ্যের বাইরে রয়েছেন।

$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf

আরও বেশ কয়েকটি বিকল্প বিকল্প রয়েছে। সহজতমগুলি কেবল আরএম এবং গ্লোববিংয়ের সাথে জড়িত ।

  • আদেশ

    rm -- *
    

    ঠিক যেমনটি কাজ করবে ঠিক তেমন কাজ করবে, যেখানে --সংকেত দেয় যে তার পরে সমস্ত কিছু একটি বিকল্প হিসাবে ব্যাখ্যা করা উচিত নয়।

    এটি এখন প্রায় দুই দশক ধরে পসিক্স ইউটিলিটি সিনট্যাক্স নির্দেশিকাগুলির অংশ। এটি বিস্তৃত, তবে এটি সর্বত্র উপস্থিত হওয়ার আশা করা উচিত নয়।

  • আদেশ

    rm ./*
    

    গ্লোবকে আলাদাভাবে প্রসারিত করে তোলে এবং তাই ডাকা ইউটিলিটি থেকে কোনও সমর্থন প্রয়োজন।

    উপরের থেকে আমার উদাহরণের জন্য, আপনি কমান্ডটি দেখতে পাবেন যা শেষ পর্যন্ত প্রতিধ্বনিত ইকো দ্বারা কার্যকর করা হবে ।

    $ echo rm ./*
    rm ./a ./b ./-rf
    

    নেতৃস্থানীয় কোনও ফাইলের নামের সাথে বিকল্পগুলির মতো দুর্ঘটনাক্রমে চিকিত্সা করা থেকে আরএমকে./ বাধা দেয় ।


1
খুব ভাল পয়েন্ট, এর সাথে ফাইলের নামগুলি - প্রসারণের পরে পতাকাগুলিতে পরিণত হয় rm। +1
সের্গেই কলডিয়াজনি 6

1
এমনকি nastier: touch 'foo -rf .. bar। আমি মনে করি না কোনও আক্রমণকারী পিতামাতার ডিরেক্টরি থেকে আরও উচ্চতর পেতে পারে, যদি না আমরা lsএর আউটপুটে কোনও পথ বিভাজক তৈরি করতে পারি ।
পিটার কর্ডস

@ পিটার আক্রমণকারীকে প্রথমে পেটেন্ট ডিরেক্টরি সরানোর জন্য লেখার অনুমতি থাকতে হবে, না?
সের্গেই কলডিয়াজনি

1
@ পিটারকর্ডস আমি নিশ্চিত নই যে rm এর সমস্ত সংস্করণে এই ব্যর্থতা রয়েছে কিনা , তবে উবুন্টু, ওপেনসুএস এবং ফেডোরায় , এটি rm: refusing to remove '.' or '..' directory: skipping '..'প্যারেন্ট ডিরেক্টরিটি সরানোর চেষ্টা করার সময় বা অনুরূপ কিছু ছিল।
ডেনিস

@ সার্জ: আক্রমণকারী আপনাকে কেবলমাত্র সেই ফাইল নামটির সাথে একটি জিপ প্রেরণ করবে এবং আপনাকে এটি বের করে এবং তারপরে সামগ্রীগুলি মুছতে চেষ্টা করে নিজেকে পায়ে গুলি করতে দেয়। অথবা / var / tmp বা অন্য কোনও ক্ষেত্রে সেই ফাইলের নাম তৈরি করে।
পিটার কর্ডেস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.