फ़ाइलों को हटाने के लिए 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)"उदाहरण केवल तभी काम करता है जब निर्देशिका में केवल एक फ़ाइल हो। आप फ़ाइल नाम का विस्तार करने के लिए केवल टैब-पूर्णता का उपयोग कर सकते हैं क्योंकि यह एकमात्र पूर्णता है।
पीटर कॉर्ड्स

@PeterCordes वास्तव में, एक अजीब कारण के लिए यह केवल एक फ़ाइल के साथ काम करता है। यह प्रयोग करने के खिलाफ एक और तर्क है ls:) मैं इसे संपादित करूंगा
सर्जियो कोलोडियाज़नी सिप

मैं इसे एक अजीब कारण नहीं कहूंगा: आप या तो $(ls)शब्द विभाजन को निष्क्रिय करने के लिए उद्धृत करते हैं, या आप शब्द-विभाजन को (विनाशकारी परिणामों के साथ) होने देते हैं। डेटा को बिना कोड के कई तारों की सूची में पास करने का एकमात्र साफ तरीका है सरणी चर, या \0एक विभाजक के रूप में, लेकिन शेल स्वयं ऐसा नहीं कर सकता है। अभी भी IFS=$'\n'कम से कम खतरनाक है, लेकिन मेल नहीं खा सकता find -print0 | xargs -0। या grep -l --null। या आप इस तरह की चीजों के साथ पूरे मामले से बचते हैं find -exec rm {} +। ( +आरएम के प्रत्येक आह्वान के लिए कई आर्ग पास करने के लिए ध्यान दें ; और अधिक कुशल)।
पीटर कॉर्ड्स

@PeterCordes हाँ, पूरी तरह से वहाँ सहमत हुए। लेकिन IFS=$'\n'इस मामले में भी विफल हो जाएगा, क्योंकि मैं फ़ाइल नाम में newline है, इसलिए शब्दों को एक के बजाय दो फ़ाइल नाम के रूप में माना जाएगा। अजीब कारण, हालांकि, यह तथ्य है कि डिफ़ॉल्ट के साथ IFSजो अंतरिक्ष, टैब, न्यूलाइन है, मूल rm "$(ls)"को भी विफल होना चाहिए, इसे ऐसे व्यवहार करना चाहिए जैसे मैंने फाइलनेम को दो अलग-अलग लोगों के रूप में कहा था, लेकिन यह नहीं हुआ। आमतौर पर मैं उपयोग findके साथ -exec, या find . . .-print0 | while IFS= read -d'' FILENAME ; do . . . doneसंरचना फ़ाइल नाम से निपटने के लिए। या एक का उपयोग कर सकते हैं python, मैं उस का उदाहरण जोड़ दिया है।
सेर्गेई कोलोडियाज़नी 15

"$(ls)"हमेशा एक arg तक फैलता है क्योंकि उद्धरण $(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 -- *
    

    ठीक उसी तरह काम करेगा, जैसा --कि संकेत देता है कि विकल्प के रूप में व्याख्या के बाद सब कुछ नहीं होना चाहिए।

    यह अब दो दशकों से अधिक POSIX उपयोगिता वाक्यविन्यास दिशानिर्देशों का हिस्सा है। यह व्यापक है, लेकिन आपको इसे हर जगह मौजूद होने की उम्मीद नहीं करनी चाहिए।

  • आदेश

    rm ./*
    

    ग्लोब का विस्तार अलग तरह से होता है और इस तरह से यूटिलिटी से कोई सपोर्ट नहीं चाहिए।

    ऊपर से मेरे उदाहरण के लिए, आप उस कमांड को देख सकते हैं जो अंततः गूंज से बहती हुई होगी ।

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

    अग्रणी आरएम को गलती से विकल्पों में से किसी भी फ़ाइल नाम के साथ व्यवहार करने से ./रोकता है ।


1
बहुत अच्छा बिंदु, विस्तार के बाद झंडे के साथ - फिल्नाम rm। +1
सर्गी कोलोडाज़नी

1
यहां तक ​​कि नास्टियर touch 'foo -rf .. bar:। मुझे नहीं लगता कि एक हमलावर को मूल निर्देशिका की तुलना में कोई भी अधिक मिल सकता है, जब तक कि हम lsआउटपुट में पथ विभाजक नहीं बना सकते ।
पीटर कॉर्ड्स

@Peter हमलावर को पहली जगह में पेटेंट निर्देशिका को हटाने के लिए लिखने की अनुमति होनी चाहिए, नहीं?
सर्गी कोलोडियाज़नी

1
@PeterCordes मुझे यकीन नहीं है कि अगर rm के सभी संस्करणों में यह विफल रहता है , लेकिन Ubuntu, OpenSUSE, और Fedora पर, यह rm: refusing to remove '.' or '..' directory: skipping '..'माता-पिता की निर्देशिका को हटाने की कोशिश करते समय ऐसा ही कुछ कहता है ।
डेनिस

@ शेर: हमलावर आपको सिर्फ एक .zip उस फ़ाइलनाम के साथ भेजता है और आपको इसे निकालने के द्वारा पैर में गोली मारता है और फिर सामग्री को हटाने की कोशिश करता है। या उस फ़ाइल नाम को / var / tmp या किसी चीज़ में बनाकर।
पीटर कॉर्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.