ফাঁকা ফাঁকা ফাইলগুলির সাথে লুপের জন্য ব্রেক, কমান্ড সন্ধান করুন


34

আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা একাধিক সাবফোল্ডার এবং আর্কাইভের সমস্ত ফাইল ট্যারে অনুসন্ধান করে। আমার স্ক্রিপ্টটি হ'ল

for FILE in `find . -type f  -name '*.*'`
  do
if [[ ! -f archive.tar ]]; then

  tar -cpf archive.tar $FILE
else 
  tar -upf archive.tar $FILE 
fi
done

ফাইন্ড কমান্ড আমাকে নিম্নলিখিত আউটপুট দেয়

find . -type f  -iname '*.*'
./F1/F1-2013-03-19 160413.csv
./F1/F1-2013-03-19 164411.csv
./F1-FAILED/F2/F1-2013-03-19 154412.csv
./F1-FAILED/F3/F1-2011-10-02 212910.csv
./F1-ARCHIVE/F1-2012-06-30 004408.csv
./F1-ARCHIVE/F1-2012-05-08 190408.csv

কিন্তু ফাইল পরিবর্তনশীল শুধুমাত্র পাথ প্রথম অংশ সঞ্চয় করে ./F1/F1-2013-03-19 এবং তারপর পরবর্তী অংশ 160413.csv

আমি readকিছুক্ষণ লুপ ব্যবহার করে চেষ্টা করেছি ,

while read `find . -type f  -iname '*.*'`;   do ls $REPLY; done

তবে আমি নিম্নলিখিত ত্রুটি পেয়েছি

bash: read: `./F1/F1-2013-03-19': not a valid identifier

কেউ বিকল্প উপায় বলতে পারেন?

হালনাগাদ

নীচের উত্তরে প্রস্তাবিত হিসাবে আমি স্ক্রিপ্টগুলি আপডেট করেছি

#!/bin/bash

INPUT_DIR=/usr/local/F1
cd $INPUT_DIR
for FILE in "$(find  . -type f -iname '*.*')"
do
archive=archive.tar

        if [ -f $archive ]; then
        tar uvf $archive "$FILE"
        else
        tar -cvf $archive "$FILE"
        fi
done

আমি যে আউটপুট পাই তা হ'ল

./test.sh
tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors

4
IFS=$'\n'লুপের জন্য প্রতিটি লাইনকে পার্স করার জন্য আপনার আগে সেট করা উচিত বলে মনে হচ্ছে
কিরি

1
হেরস নামে কিছু প্রাসঙ্গিক পাঠ: mywiki.wooledge.org/ParsingLs এবং dwheeler.com/essays/filenames-in-shell.html এবং unix.stackexchange.com/questions/128985/why-not-parse-ls
Sergiy Kolodyazhnyy

উত্তর:


36

এখানে ভুল পদ্ধতির forসাথে ব্যবহার করে findদেখুন, উদাহরণস্বরূপ আপনি কীটগুলি কীভাবে খুলছেন তা সম্পর্কে এই লিখনআপটি দেখুন ।

প্রস্তাবিত পদ্ধতির ব্যবহার করা find, whileএবং readহিসাবে বর্ণনা এখানে । নীচে একটি উদাহরণ যা আপনার জন্য কাজ করা উচিত:

find . -type f -name '*.*' -print0 | 
while IFS= read -r -d '' file; do
    printf '%s\n' "$file"
done

আপনি নাল ( \0) অক্ষর দিয়ে ফাইলের নামগুলি এইভাবে সীমাবদ্ধ করেন , এর অর্থ হল যে স্থান এবং অন্যান্য বিশেষ অক্ষরগুলির পার্থক্য সমস্যার কারণ হবে না।

যে ফাইলগুলি findসন্ধান করে সেগুলি সহ একটি সংরক্ষণাগার আপডেট করার জন্য , আপনি এর আউটপুটটি সরাসরি এটিকে পাস করতে পারেন tar:

find . -type f -name '*.*' -printf '%p\0' | 
tar --null -uf archive.tar -T -

নোট করুন যে সংরক্ষণাগারটি বিদ্যমান থাকলে বা না থাকলে আপনার মধ্যে পার্থক্য করতে tarহবে না, এটি এটিকে সংবেদনশীলভাবে পরিচালনা করবে। সংরক্ষণাগারটিতে কিছুটা -printfঅন্তর্ভুক্ত না করার জন্য এখানকার ব্যবহারটিও নোট করুন ./


ধন্যবাদ, এটি প্রায় কার্যকর। একমাত্র জিনিসটি তার ./হিসাবে আর্কাইভ করা । ./.tar tar: ./archive.tar: file is the archive; not dumped
উবুন্টুসার

@ উবুন্টুসার আপনি দেখতে একটি সাধারণ চেক যোগ করতে পারেনif [[ "$FILE" == "./" ]]; then continue
কিরি

@ উবুন্টুসার: আপডেট হওয়া উত্তর দেখে আপনি ./কিছুটা এড়াতে পারবেন -printf। তবে এটি অন্তর্ভুক্ত করা হয় কিনা বা এটি কেবল বর্তমান ডিরেক্টরিটিকে উল্লেখ করে তবে তাতে কোনও পার্থক্য করা উচিত নয়। find/tarআপনি একটি বিকল্প সংমিশ্রণও অন্তর্ভুক্ত করেছিলেন যা আপনি ব্যবহার করতে পারেন।
থোর

আপনারা sortপুনরাবৃত্তি করার আগে ফলাফলগুলি চাওয়ার sort -zজন্য আপনার নাল বিভাজক প্রয়োজন।
অ্যাডামিন

13

এর forমতো লুপটি উদ্ধৃত করার চেষ্টা করুন :

for FILE in "`find . -type f  -name '*.*'`"   # note the quotation marks

উদ্ধৃতি ব্যতীত, বাশ স্পেস এবং নিউলাইনগুলি ( \n) মোটেও হ্যান্ডেল করে না ...

এছাড়াও সেট করার চেষ্টা করুন

IFS=$'\n'

1
1 আইএফএসের জন্য +1। যা বিভাজক চরিত্রকে বর্জন করে।
রায়

1
এটি আমার জন্য কাজ করা সমাধান। আমি commবাছাই করা ফাইল তালিকার তুলনা করতে ব্যবহার করছি এবং ফাইলের নামগুলির মধ্যে ফাঁকা স্থান রয়েছে, ভেরিয়েবলগুলি উদ্ধৃত করেও এটি কাজ করছে না। তারপরে আমি সাইবারসিটি.বিজ / টিপস / হ্যান্ডলিং-ফাইল-নামগুলি- স্পেসস- ইন -বাশ এইচটিএমএল এবং আইএফএস = $ (প্রতিধ্বনিত "\ n \ b") এর সাথে $ আইএফএস স্থাপনের সমাধানটি আমার পক্ষে কাজ করে দেখলাম ।
পিবিএইচজে

ডাবল উদ্ধৃতি যোগ, মার্জিত, সহজ, সুন্দর - ধন্যবাদ!
বড় ধনী

8

এটি কার্যকর এবং সহজ:

find . -name '<pattern>' | while read LINE; do echo "$LINE" ; done

এই উত্তরের জন্য রূপাকে ( https://github.com/rupa/z ) ক্রেডিট করুন ।


4

যথাযথ উদ্ধৃতি ছাড়াও, আপনি findএকটি ন্যূন পৃথককারী ব্যবহার করতে বলতে পারেন, এবং তারপরে একটি whileলুপে ফলাফলগুলি পড়তে এবং প্রক্রিয়া করতে পারেন

while read -rd $'\0' file; do
    something with "$file"
done < <(find  . -type f -name '*.*' -print0)

এটি POSIX- অনুবর্তী যে কোনও ফাইলের নাম পরিচালনা করতে হবে - দেখুন man find

   -print0
          True; print the full file name on the standard output, followed by a null character (instead of the newline character that  -print  uses).   This  allows  file
          names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output.  This option corresponds to the
          -0 option of xargs.

এটি কেবলমাত্র আমার জন্য কার্যকর সমাধান। ধন্যবাদ।
কোডফ্রেক


1

স্পেস থাকতে পারে এমন ফাইলগুলি খুঁজতে আমি এটির মতো কিছু করেছি।

IFS=$'\n'
for FILE in `/usr/bin/find $DST/shared -name *.nsf | grep -v bookmark.nsf | grep -v names.nsf`; do
    file $FILE | tee -a $LOG
done

কবজির মতো কাজ করেছেন :)


0

ফাইলের নামটিতে একটি নতুন লাইন অক্ষর থাকলে এখানে বেশিরভাগ উত্তরগুলি বিরতি। আমি আরও 15 বছর ব্যাশ ব্যবহার করি তবে কেবল ইন্টারেক্টিভ।

পাইথনে আপনি আমাদের os.walk (): http://docs.python.org/2/library/os.html#os.walk করতে পারেন

এবং টারফাইল মডিউল: http://docs.python.org/2/library/tarfile.html#tar- উদাহরণ


0

আমি মনে করি আপনি find'এস-এক্সেক বিকল্পটি ব্যবহার করে ভাল হতে পারেন ।

find . -type f -name '*.*' -exec tar -cpf archive.tar {} +

তারপরে একটি সিস্টেম কল ব্যবহার করে কমান্ডটি কার্যকর করে, যাতে স্পেস এবং নিউলাইনগুলি সংরক্ষণ করা হয় (বরং একটি পাইপ, যার জন্য বিশেষ অক্ষরের উদ্ধৃতি প্রয়োজন)। নোট করুন যে সংরক্ষণাগারটি ইতিমধ্যে বিদ্যমান আছে কিনা এবং "টার-সি" কাজ করে এবং এটি (কমপক্ষে ব্যাশ সহ) না {। বা + উদ্ধৃত করার দরকার নেই।


-1

Minerz029 হিসাবে পরামর্শ হিসাবে, আপনাকে কমান্ডের প্রসারকে উদ্ধৃত করতে হবে find$FILEআপনার লুপের সমস্ত বিকল্পগুলি উদ্ধৃত করতে হবে ।

for FILE in "$(find . -type f  -name '*.*')"
do
    if [ ! -f archive.tar ]; then
        tar -cpf archive.tar "$FILE"
    else 
        tar -upf archive.tar "$FILE" 
    fi
done

নোট করুন যে $()সিনট্যাক্সটি ব্যাকটিক্স ব্যবহারের ক্ষেত্রে পছন্দ করা উচিত; দেখতে এই ইউ & এল প্রশ্ন । আমি [[কীওয়ার্ডটিও সরিয়ে নিয়েছি এবং [কমান্ড দ্বারা এটি প্রতিস্থাপন করেছি কারণ এটি পসিক্স।


সম্পর্কে [[এবং [এটি দেখে মনে হয় এটি [[আরও নতুন এবং গ্লোব্বিং এবং রেজেক্স ম্যাচের মতো আরও বৈশিষ্ট্যগুলিকে সমর্থন করে। [[কেবলমাত্র এতে রয়েছে bash, যদিও নেইsh
কিরি

@ minerz029 হ্যাঁ সেটাই আমি বলছি. [[গ্লোববিং সমর্থন করে আপনি কী বোঝাতে চেয়েছেন তা আমি জানি না । গ্রেগের উইকির মতে , ভিতরে কোনও গ্লোববিং হয় না [[
জোসেফ আর।

[ "ab" == a? ] && echo "true"তারপরে চেষ্টা করুন[[ "ab" == a? ]] && echo "true"
কিরি

@ minerz029 এটি গ্লোবিং নয়। এগুলি নিয়মিত এক্সপ্রেশন (আলগাভাবে ব্যাখ্যা করা)। এটি কোনও গ্লোব নয় কারণ a*"" সমস্ত ফাইল যার নাম দিয়ে শুরু হয় aএবং তারপরে কোনও সংখ্যক অক্ষর থাকে "তার পরিবর্তে" কোনও সংখ্যক অক্ষর অনুসরণ করে "means [ ab = a* ] && echo true বনাম চেষ্টা করুন [[ ab == a* ]] && echo true
জোসেফ আর।

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