নির্দিষ্ট এক্সটেনশান সহ ফাইলগুলি মুছতে পুনরাবৃত্তভাবে কোনও ডিরেক্টরি কীভাবে লুপ করবেন


157

আমার পুনরাবৃত্তভাবে একটি ডিরেক্টরিতে লুপ করতে হবে এবং এক্সটেনশন সহ সমস্ত ফাইল সরিয়ে ফেলতে হবে .pdf এবং এবং.doc । আমি একটি ডিরেক্টরি পুনরাবৃত্তির সাথে লুপ পরিচালনা করছি তবে উপরের উল্লিখিত ফাইল এক্সটেনশনগুলির সাথে ফাইলগুলি ফিল্টার করার ব্যবস্থা করছি না।

আমার কোড এখন পর্যন্ত

#/bin/sh

SEARCH_FOLDER="/tmp/*"

for f in $SEARCH_FOLDER
do
    if [ -d "$f" ]
    then
        for ff in $f/*
        do      
            echo "Processing $ff"
        done
    else
        echo "Processing file $f"
    fi
done

কোডটি পূরণ করতে আমার সাহায্যের দরকার, যেহেতু আমি কোথাও পাচ্ছি না।


68
আমি জানি কোডটি না বুঝে এটি সম্পাদন করা খারাপ ফর্ম, তবে প্রচুর লোক বাশ স্ক্রিপ্টিং শিখতে এই সাইটে আসে। আমি এখানে "বাশ স্ক্রিপ্টিং ফাইলগুলি পুনরাবৃত্তভাবে" গুগল করে পেয়েছি এবং এটির মধ্যে ফাইলগুলি মুছে ফেলা হবে বুঝতে না পেরে প্রায় এইগুলির মধ্যে একটি উত্তর (কেবল পুনরাবৃত্তি পরীক্ষা করার জন্য) চালিয়েছি। আমি জানি rmওপি কোডের একটি অংশ, তবে এটি জিজ্ঞাসিত প্রশ্নের সাথে আসলে প্রাসঙ্গিক নয়। আমার মনে হয় যদি কোনও ক্ষতিকারক কমান্ড ব্যবহার করে উত্তরগুলি অঙ্কিত হয় তবে এটি নিরাপদ হবে echo
কিথ

এখানে একই প্রশ্ন: stackoverflow.com/questions/41799938/...
codeforester

1
@ কিথের অনুরূপ অভিজ্ঞতা ছিল, পুরোপুরি সম্মত এবং শিরোনামটি বদলে
ইডকলিভ 463035818

উত্তর:


146

find স্রেফ তার জন্য তৈরি

find /tmp -name '*.pdf' -or -name '*.doc' | xargs rm

19
অথবা সন্ধানের -deleteবিকল্প।
ম্যাথু ফ্ল্যাশেন

28
এক সর্বদা ব্যবহার করা উচিত find ... -print0 | xargs -0 ..., কাঁচা সন্ধান নয় | এক্সরেগস নিউলাইনলাইনযুক্ত ফাইল নামগুলির সাথে সমস্যা এড়াতে।
গ্রুম্বেল

7
xargsকোনও বিকল্প ছাড়াই ব্যবহার করা প্রায়শই খারাপ পরামর্শ এবং এটি কোনও ব্যতিক্রম নয়। find … -execপরিবর্তে ব্যবহার করুন।
গিলস

211

মউভিচিলের উত্তরের অনুসরণ হিসাবে, আপনি জার্গস ব্যবহার না করে লুপের জন্য এটি হিসাবেও করতে পারেন। আমি প্রায়শই xargs বোঝার মতো দেখতে পাই, বিশেষত যদি প্রতিটি পুনরাবৃত্তিতে আমাকে আরও জটিল কিছু করার প্রয়োজন হয়।

for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm $f; done

যেহেতু বেশিরভাগ লোক মন্তব্য করেছেন, ফাইলের নামগুলিতে শূন্যস্থান থাকলে এটি ব্যর্থ হবে। আপনি অস্থায়ীভাবে আইএফএস (অভ্যন্তরীণ ক্ষেত্রের পৃথক )টিকে নতুন লাইন চরিত্রে সেট করে এটিকে ঘিরে কাজ করতে পারেন। \[?*ফাইলের নামগুলিতে ওয়াইল্ডকার্ড অক্ষর থাকলে এটিও ব্যর্থ হয় । অস্থায়ীভাবে ওয়াইল্ডকার্ড সম্প্রসারণ (গ্লোব্বিং) অক্ষম করে আপনি এটিকে ঘিরে কাজ করতে পারেন।

IFS=$'\n'; set -f
for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm "$f"; done
unset IFS; set +f

যদি আপনার ফাইলনামগুলিতে নিউলাইনগুলি থাকে তবে তা আর কাজ করবে না। আপনি একটি xargs ভিত্তিক সমাধান সঙ্গে ভাল বন্ধ:

find /tmp \( -name '*.pdf' -or -name '*.doc' \) -print0 | xargs -0 rm

(পাল্টা বন্ধনী -print0উভয় orধারা প্রয়োগ করতে এখানে প্রয়োজন ।)

জিএনইউ এবং * বিএসডি সন্ধানেও একটি -deleteক্রিয়া রয়েছে, যা দেখতে এই রকম দেখাবে:

find /tmp \( -name '*.pdf' -or -name '*.doc' \) -delete

27
ফাইলের নামের মধ্যে কোনও স্থান থাকলে এটি প্রত্যাশার মতো কাজ করে না (লুপের জন্য হোয়াইটস্পেসে সন্ধানের ফলাফলগুলি বিভক্ত করে)।
ট্র্যাভ

3
আপনি হোয়াইট স্পেসে এভয়েড বিভাজন কীভাবে করবেন? আমি অনুরূপ জিনিসটি চেষ্টা করছি এবং আমার অনেকগুলি ডিরেক্টরি রয়েছে যেখানে এই লুপটিকে স্ক্রুপ করে তোলে ites
খ্রিস্টান

3
কারণ এটি একটি খুব সহায়ক উত্তর?
জেনপার্টু

1
@ ক্রিশ্চিয়ান এই জাতীয় উক্তি ব্যবহার করে হোয়াইটস্পেস বিভক্তকরণ ঠিক করুন: "$ (সন্ধান করুন ...)"। আমি জেমস এর উত্তর সম্পাদনা করেছি।
ম্যাথু

2
@ আপনার সম্পাদনা কিছুতেই কিছু ঠিক করেনি: এটি অনন্যরূপে পাওয়া কোন ফাইল থাকলে কমান্ডটি কেবলমাত্র কাজ করে । ফাইলের নামগুলিতে কোনও স্থান, ট্যাব, ইত্যাদি না থাকলে কমপক্ষে এই সংস্করণটি কাজ করে । আমি পুরানো সংস্করণে ফিরে এসেছি। বুদ্ধিমান হিসাবে চিহ্নিত করা সত্যিই একটি ঠিক করতে পারে for f in $(find ...)শুধু এই পদ্ধতিটি ব্যবহার করবেন না।
gniourf_gniourf

67

ছাড়া find:

for f in /tmp/* tmp/**/* ; do
  ...
done;

/tmp/*ডিয়ার /tmp/**/*ফাইল এবং সাবফোল্ডারগুলিতে ফাইল। এটি সম্ভব যে আপনাকে গ্লোবস্টার বিকল্পটি সক্ষম করতে হবে ( shopt -s globstar)। সুতরাং প্রশ্নের জন্য কোডটি দেখতে এমন হওয়া উচিত:

shopt -s globstar
for f in /tmp/*.pdf /tmp/*.doc tmp/**/*.pdf tmp/**/*.doc ; do
  rm "$f"
done

নোট করুন যে এর জন্য বাশ ≥4.0 (বা zsh ছাড়াই shopt -s globstar, বা ksh এর set -o globstarপরিবর্তে shopt -s globstar) দরকার। তদ্ব্যতীত, ব্যাশ <৪.৩ এ, এটি ডিরেক্টরিগুলি পাশাপাশি ডিরেক্টরিগুলিতে প্রতীকী লিঙ্কগুলি সন্ধান করে যা সাধারণত কাঙ্ক্ষিত হয় না।


1
এই পদ্ধতিটি আমার পক্ষে কাজ করেছে, এমনকি ওএসএক্স
আইডিয়াসাইলাম

2
লক্ষণীয় যে গ্লোবস্টারটি কেবল বাশ ৪.০ বা আরও নতুন ক্ষেত্রে পাওয়া যায় .. যা অনেকগুলি মেশিনে ডিফল্ট সংস্করণ নয়।
ট্রয় হাওয়ার্ড

1
আমি মনে করি না আপনি প্রথম যুক্তি নির্দিষ্ট করতে হবে। (কমপক্ষে আজ হিসাবে,) for f in /tmp/**যথেষ্ট হবে। / Tmp ডায়ারের ফাইল অন্তর্ভুক্ত করে।
ফিল্ড 294

1
এর চেয়ে ভাল কি হবে না? for f in /tmp/*.{pdf,doc} tmp/**/*.{,pdf,doc} ; do
বরফ-ব্লেজ

1
**একটি দুর্দান্ত এক্সটেনশন তবে পসিক্সের কাছে বহনযোগ্য নয় sh। (এই প্রশ্নের বাঁধা হয় ব্যাশ । কিন্তু এটা যে বাতলান সমাধান এখানে বেশ কয়েক অসদৃশ, এই সত্যিই ব্যাশ শুধুমাত্র বা সুন্দর হতে পারে, ভাল, এটা বেশ কয়েকটি বর্ধিত শাঁস এ ছাড়া, এও কাজ করে।)
tripleee

27

যদি আপনি পুনরাবৃত্তভাবে কিছু করতে চান তবে আমি আপনাকে পুনরাবৃত্তি ব্যবহার করার পরামর্শ দিচ্ছি (হ্যাঁ, আপনি এটি স্ট্যাকগুলি এবং এগুলি ব্যবহার করে করতে পারেন তবে হেই)।

recursiverm() {
  for d in *; do
    if [ -d "$d" ]; then
      (cd -- "$d" && recursiverm)
    fi
    rm -f *.pdf
    rm -f *.doc
  done
}

(cd /tmp; recursiverm)

এটি বলেছে, findসম্ভবত এটি আরও ভাল পছন্দ হিসাবে ইতিমধ্যে পরামর্শ দেওয়া হয়েছে।


15

শেল ( bash) ব্যবহার করে এখানে একটি উদাহরণ দেওয়া হল :

#!/bin/bash

# loop & print a folder recusively,
print_folder_recurse() {
    for i in "$1"/*;do
        if [ -d "$i" ];then
            echo "dir: $i"
            print_folder_recurse "$i"
        elif [ -f "$i" ]; then
            echo "file: $i"
        fi
    done
}


# try get path from param
path=""
if [ -d "$1" ]; then
    path=$1;
else
    path="/tmp"
fi

echo "base path: $path"
print_folder_recurse $path

15

এটি সরাসরি আপনার প্রশ্নের উত্তর দেয় না, তবে আপনি ওয়ান-লাইনার দিয়ে আপনার সমস্যার সমাধান করতে পারেন:

find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -exec rm {} +

সন্ধানের কয়েকটি সংস্করণে (জিএনইউ, বিএসডি) একটি -deleteক্রিয়া রয়েছে যা আপনি কল করার পরিবর্তে ব্যবহার করতে পারেন rm:

find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -delete

7

এই পদ্ধতিটি স্পেসগুলি ভালভাবে পরিচালনা করে।

files="$(find -L "$dir" -type f)"
echo "Count: $(echo -n "$files" | wc -l)"
echo "$files" | while read file; do
  echo "$file"
done

সম্পাদনা করুন, একের পর এক স্থির করুন

function count() {
    files="$(find -L "$1" -type f)";
    if [[ "$files" == "" ]]; then
        echo "No files";
        return 0;
    fi
    file_count=$(echo "$files" | wc -l)
    echo "Count: $file_count"
    echo "$files" | while read file; do
        echo "$file"
    done
}

আমি মনে করি প্রতিধ্বনি পরে "-n" পতাকা লাগবে না। কেবল এটি নিজেই পরীক্ষা করুন: "-n" দিয়ে আপনার স্ক্রিপ্টটি ভুল সংখ্যক ফাইল দেয়। ডিরেক্টরিতে ঠিক একটি ফাইলের জন্য এটি "গণনা: 0"
লোপা

1
এটি সমস্ত ফাইলের নামের সাথে কাজ করে না: এটি নামের শেষে ফাঁকা স্থানগুলিতে, নিউলাইনযুক্ত ফাইলের নাম এবং ব্যাকস্ল্যাশযুক্ত কিছু ফাইলের নাম সহ ব্যর্থ হয়। এই ত্রুটিগুলি সংশোধন করা যেতে পারে তবে পুরো পদ্ধতির অযথা জটিল কারণ এটি বিরক্ত করার মতো নয়।
গিলস

3

বাশের জন্য (সংস্করণ 4.0)

shopt -s globstar nullglob dotglob
echo **/*".ext"

এখানেই শেষ.
সেই এক্সটেনশান সহ ফাইলগুলি (বা ডায়ারস) নির্বাচন করতে সেখানে অনুগামী এক্সটেনশানটি "অনুগ্রহ করে"।

বিকল্প গ্লোবস্টার ** (পুনরাবৃত্তি অনুসন্ধান করুন) সক্রিয় করে।
অপশন নালগ্লোব একটি * সরিয়ে দেয় যখন এটি কোনও ফাইল / ডির সাথে মেলে না।
বিকল্প ডটগ্লোব এমন ফাইল অন্তর্ভুক্ত করে যা ডট (লুকানো ফাইল) শুরু করে।

সাবধান হন যে ব্যাশ ৪.৩ এর আগে, **/ডিরেক্টরিগুলির মধ্যে প্রতীকী লিঙ্কগুলিও ট্র্যাভার করে যা পছন্দসই নয়।


1

নিম্নলিখিত ফাংশনটি ডিরেক্টরিটির সমস্ত ডিরেক্টরিতে পুনরাবৃত্তভাবে পুনরাবৃত্তি করবে \home\ubuntu(উবুন্টুর অধীনে পুরো ডিরেক্টরি কাঠামো) এবং elseব্লকটিতে প্রয়োজনীয় চেক প্রয়োগ করবে ।

function check {
        for file in $1/*      
        do
        if [ -d "$file" ]
        then
                check $file                          
        else
               ##check for the file
               if [ $(head -c 4 "$file") = "%PDF" ]; then
                         rm -r $file
               fi
        fi
        done     
}
domain=/home/ubuntu
check $domain

1

এটি করতে আমি জানি এটি সহজতম উপায়: rm **/@(*.doc|*.pdf)

** এই কাজটি পুনরাবৃত্তি করে তোলে

@(*.doc|*.pdf) পিডিএফ বা ডকটিতে শেষ হওয়া কোনও ফাইলের সন্ধান করুন

এর rmসাথে প্রতিস্থাপন করে নিরাপদে পরীক্ষা করা সহজls


0

findঅন্য কোনও ইউটিলিটিতে আউটপুট পাইপ করার কোনও কারণ নেই । এটিতে findএকটি -deleteপতাকা নির্মিত হয়েছে।

find /tmp -name '*.pdf' -or -name '*.doc' -delete

0

প্রদত্ত অন্যান্য উত্তরগুলিতে এমন ফাইল বা ডিরেক্টরিগুলি অন্তর্ভুক্ত করা হবে না যা এর সাথে শুরু হয়। নিম্নলিখিত আমার জন্য কাজ করেছে:

#/bin/sh
getAll()
{
  local fl1="$1"/*;
  local fl2="$1"/.[!.]*; 
  local fl3="$1"/..?*;
  for inpath in "$1"/* "$1"/.[!.]* "$1"/..?*; do
    if [ "$inpath" != "$fl1" -a "$inpath" != "$fl2" -a "$inpath" != "$fl3" ]; then 
      stat --printf="%F\0%n\0\n" -- "$inpath";
      if [ -d "$inpath" ]; then
        getAll "$inpath"
      #elif [ -f $inpath ]; then
      fi;
    fi;
  done;
}

-1

শুধু কর

find . -name '*.pdf'|xargs rm

4
না, এটা করবেন না। স্পেস বা অন্যান্য মজার চিহ্ন সহ আপনার ফাইলের নাম থাকলে এটি বিরতি দেয়।
gniourf_gniourf

-1

নিম্নলিখিত প্রদত্ত ডিরেক্টরিটি পুনরাবৃত্তভাবে লুপ করবে এবং সমস্ত সামগ্রী তালিকাভুক্ত করবে:

for d in /home/ubuntu/*; do echo "listing contents of dir: $d"; ls -l $d/; done


না, এই ফাংশনটি পুনরাবৃত্তির সাথে কোনও কিছুকেই পিছনে ফেলে না। এটি কেবলমাত্র উপ-ডিরেক্টরিগুলির বিষয়বস্তু তালিকাভুক্ত করে। এটি প্রায় চারপাশে fluff ls -l /home/ubuntu/*/, তাই এটি বেশ অকেজো।
গিলস

-1

আপনি যদি কমান্ডটি চালাতে ব্যবহৃত শেল পরিবর্তন করতে পারেন তবে আপনি কাজটি করতে ZSH ব্যবহার করতে পারেন।

#!/usr/bin/zsh

for file in /tmp/**/*
do
    echo $file
done

এটি পুনরাবৃত্তভাবে সমস্ত ফাইল / ফোল্ডার লুপ করবে will

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