আরএম কমান্ড লাইনে কাজ করে তবে স্ক্রিপ্টে নয়


11

আমি যখন rm *.old.*কমান্ড লাইনে করি তখন এটি সঠিকভাবে মুছে ফেলা হয়, কিন্তু যখন আমি আমার স্ক্রিপ্টের নিম্নলিখিত অংশে এটি করি তখন এটি সমস্ত *.old.*ফাইল আরএম করে না ।

আমার বাশ স্ক্রিপ্টে কী ভুল:

 for i in ./*; do
    if [[ -f $i ]];  then

        if [[ $i  ==  *.old.* ]]; then
                oldfile=$i
                echo "this file is to be removed: $oldfile"
                rm $oldfile
                exec 2>errorfile
            if [ -s $errorfile ]
            then
                echo "rm failed"
            else
                echo "removed $oldfile!"
            fi
        else
            echo "file with old extension  does not exist"
        fi

        orig=$i
        dest=$i.old
        cp $orig $dest
        echo "Copied $i"

    else
        echo "${i} is not a file"
    fi 
done

উত্তর:


4

যদি আমি বুঝতে পারি যে আপনি কী করছেন ( .oldপ্রত্যয় সহ যে কোনও ফাইল মুছুন এবং প্রত্যয় সহ কোনও বিদ্যমান ফাইলের একটি অনুলিপি তৈরি করুন .old), আপনি পরিবর্তে সন্ধানটি ব্যবহার করতে পারেন:

#!/bin/sh

find . -maxdepth 1 -name \*.old -type f -printf "deleting %P\n" -delete
find . -maxdepth 1 -type f -printf "copying %P to %P.old\n" -exec cp '{}' '{}.old' \;

-maxdepth 0সাব-ডাইরেক্টরিগুলিতে সন্ধানকারী কমান্ডটি থামায়, -type fকেবল নিয়মিত ফাইল অনুসন্ধান করবে; -printfবার্তা তৈরি করে ( %Pফাইলের নাম পাওয়া যায়)। -exec cpকপি ফাংশন কল এবং '{}'ফাইলের নাম হল


14

আপনার স্ক্রিপ্টে বিভিন্ন সম্ভাব্য ব্যর্থতা পয়েন্ট রয়েছে। প্রথমত, সমস্ত মিলে যাওয়া ফাইলগুলির একটি তালিকা তৈরি rm *.old*করতে গ্লোববিং ব্যবহার করা হবে এবং এটি সাদা নামের স্থানের ফাইলগুলির সাথে কাজ করতে পারে। আপনার স্ক্রিপ্ট, গ্লোব প্রতিটি ফলাফলের জন্য একটি পরিবর্তনশীল বরাদ্দ করে এবং উদ্ধৃতি ছাড়াই তা করে। যদি আপনার ফাইলের নামগুলিতে সাদা স্থান থাকে তবে তা ভেঙে যাবে। উদাহরণ স্বরূপ:

$ ls
'file name with spaces.old.txt'  file.old.txt
$ rm *.old.*   ## works: both files are deleted

$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'

যেমন আপনি দেখতে পাচ্ছেন, ফাইলটির নামে ফাঁক দিয়ে লুপটি ব্যর্থ হয়েছে। এটি সঠিকভাবে করতে, আপনাকে ভেরিয়েবলটি উদ্ধৃত করতে হবে:

$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'

$iআপনার স্ক্রিপ্টে প্রতিটি ব্যবহারের ক্ষেত্রে একই সমস্যা প্রযোজ্য । আপনার সর্বদা আপনার ভেরিয়েবলগুলি উদ্ধৃত করা উচিত ।

পরবর্তী সম্ভাব্য সমস্যাটি হ'ল আপনি আশা করছেন বলে মনে হয় যে *.old.*এটি এক্সটেনশানের সাথে ফাইলগুলির সাথে মেলে .old। এটা হয় না। এটি "0 বা ততোধিক অক্ষর" ( *) এর সাথে মিলে যায়, তারপরে ক ., তারপরে "পুরাতন", তার পরে অন্যটি .এবং "আবার 0 বা ততোধিক অক্ষর"। এর অর্থ এটির মতো কিছু মিলবে নাfile.old তবে কেবল। File.old.foo এর মতো:

$ ls
file.old  file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo     

সুতরাং, কোন ম্যাচ শত্রু file.old। যে কোনও ক্ষেত্রে, আপনার স্ক্রিপ্টটি প্রয়োজনের চেয়ে অনেক জটিল। পরিবর্তে এটি ব্যবহার করে দেখুন:

#!/bin/bash

for i in *; do
    if [[ -f "$i" ]];  then
        if [[ "$i"  ==  *.old ]]; then
            rm -v "$i" || echo "rm failed for $i"
        else
            echo "$i doesn't have an .old extension"
        fi
        cp -v "$i" "$i".old
    else
        echo "$i is not a file"
    fi 
done

লক্ষ্য করুন আমি যোগ -vকরতে rmএবং CP which does the same thing as what you were doing with yourecho` বিবৃতি।

এটি নিখুঁত নয় যেহেতু আপনি যখন খুঁজে পাবেন, উদাহরণস্বরূপ, file.oldএটি মুছে ফেলা হবে এবং পরে, স্ক্রিপ্টটি এটি অনুলিপি করার চেষ্টা করবে এবং ফাইলটি আর বিদ্যমান না থাকায় ব্যর্থ হবে। তবে আপনি যা স্ক্রিপ্টটি আসলে করার চেষ্টা করছেন তা আপনি ব্যাখ্যা করেন নি তাই আপনি যদি সত্যিই কী অর্জন করার চেষ্টা করছেন আপনি আমাদের না জানান তবে আমি আপনার জন্য এটি ঠিক করতে পারছি না।

যদি আপনি যা চান তা i) .oldএক্সটেনশান সহ সমস্ত ফাইল মুছে ফেলুন এবং ii) .oldবিদ্যমান ফাইলগুলিতে এক্সটেনশনটি যুক্ত করুন , আপনার সত্যিকারের যা দরকার তা হ'ল:

#!/bin/bash

for i in *.old; do
    if [[ -f "$i" ]]; then
        rm -v "$i" || echo "rm failed for $i"
    else
        echo "$i is not a file"
    fi 
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
    if [[ -f "$i" ]]; then
        ## the -v makes cp report copied files
        cp -v "$i" "$i".old
    fi
done

আমি ফাইলগুলিকে ফাইলআলডে ব্যাকআপ দেওয়ার চেষ্টা করছি তবে একই সময়ে .old.old বা .old.old.old বা .old.old.old ইত্যাদিতে যে কোনও ফাইলের আরএম ব্যবহার করি আমি যে কমান্ডলাইনটি ব্যবহার করি rm *.old.*সেগুলি এই ফাইলগুলি সরিয়ে দেয় তবে ফাইল.ল্ড ব্যাকআপ ফাইল নয়। আমি আমার স্ক্রিপ্টে তা করার চেষ্টা করছি। ধন্যবাদ
ডন

1
@ ডোন দয়া করে আপনার প্রশ্নটি সম্পাদনা করুন এবং আরও বিশদে এটি ব্যাখ্যা করুন। উদাহরণস্বরূপ ফাইলের নাম এবং আপনার স্ক্রিপ্টটি চালানোর পরে আপনি তাদের সাথে কী হতে চান তা অন্তর্ভুক্ত করুন। আদর্শভাবে, চ্যাটে আসুন এবং আমাকে পিং করুন যাতে আমরা এটি নিয়ে আলোচনা করতে পারি।
টেরডন

8

শুধুমাত্র ক্ষেত্রেই rm $oldfileব্যর্থ হতে পারে যখন আপনার ফাইলের নাম কোন অক্ষর আছে হয় IFS(স্থান, ট্যাব, NEWLINE) অথবা কোন উল্লিখিত glob অক্ষর ( *, ?, [])।

এর কোনও অক্ষর IFSউপস্থিত থাকলে শেলটি শব্দ বিভাজন সম্পাদন করে এবং ভেরিয়েবল প্রসারণের উপর গ্লোব্বিং অক্ষরের পাথনাম বিস্তারের উপস্থিতির ভিত্তিতে কাজ করে।

সুতরাং, উদাহরণস্বরূপ, যদি ফাইলের নাম হয় তবে foo bar.old.ভেরিয়েবলটি oldfileধারণ করে foo bar.old.

যখন তুমি কর:

rm $oldfile

প্রথম টুকরা এ শেল সম্প্রসারণ oldfileদুটি শব্দ মধ্যে স্থান, fooএবং bar.old.। সুতরাং আদেশটি হয়ে যায়:

rm foo bar.old.

যা অবশ্যই অপ্রত্যাশিত ফলাফলের দিকে নিয়ে যাবে। উপায় দ্বারা, যদি আপনার কোন globbing অপারেটার (আছে যদি *, ?, []সম্প্রসারণ থেকে), তারপর পথনাম সম্প্রসারণ খুব সম্পন্ন করা হবে।

পছন্দসই ফলাফল পেতে আপনার ভেরিয়েবলগুলি উদ্ধৃত করতে হবে:

rm "$oldfile"

এখন, কোনও শব্দ বিভাজন বা পথের নাম সম্প্রসারণ করা হবে না, সুতরাং আপনার পছন্দসই ফলাফল পাওয়া উচিত অর্থাৎ পছন্দসই ফাইলটি সরানো হবে। যদি কোনও ফাইলের নাম দিয়ে শুরু হয় -, তবে এটি করুন:

rm -- "$oldfile"

আপনি জিজ্ঞাসা করতে পারেন, ভিতরে ব্যবহার করার সময় আমাদের কেন ভেরিয়েবলগুলি উদ্ধৃত করতে হবে না [[, কারণটি [[একটি bashমূলশব্দ এবং এটি প্রসারকে আক্ষরিক রেখে অভ্যন্তরীণভাবে পরিবর্তনশীল সম্প্রসারণ পরিচালনা করে।


এখন, কয়েক পয়েন্ট:

  • কমান্ডের exec 2>errorfileআগে আপনার STDERR ( ) পুনর্নির্দেশ করা উচিত rmঅন্যথায় [[ -s errorfile ]]পরীক্ষা মিথ্যা ধনাত্মকতা দেয়

  • আপনি ব্যবহার করেছেন [ -s $errorfile ], আপনি একটি পরিবর্তনশীল প্রসারণ ব্যবহার করছেন $errorfileযা NUL প্রদত্ত errorfileভেরিয়েবলটি কোথাও সংজ্ঞায়িত হয়নি। সম্ভবত আপনি [ -s errorfile ]STDERR পুনঃনির্দেশের উপর ভিত্তি করেই বোঝাতে চেয়েছিলেন

  • যদি ভেরিয়েবলটি errorfileসংজ্ঞায়িত করা হয়, ব্যবহারের সময় [ -s $errorfile ]এটি আবার উপরে উল্লিখিত কেসগুলি IFSএবং গ্লোব্বিংয়ের উপরে চোক চাপিয়ে দেয় কারণ এর বিপরীতে [[, [অভ্যন্তরীণভাবে পরিচালনা করা হয় নাbash

  • স্ক্রিপ্টের পরবর্তী অংশে, আপনি cpইতিমধ্যে মুছে ফেলা ফাইলটি (আবার ভেরিয়েবলের উদ্ধৃতি না দিয়ে) চেষ্টা করছেন, এটির কোনও মানে হয় না, আপনার সেই ছকটি পরীক্ষা করা উচিত এবং আপনার টার্গেটের ভিত্তিতে প্রয়োজনীয় সংশোধন করা উচিত।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.