কীভাবে স্বতন্ত্র লাইনে কমান্ড আউটপুট আলাদা করা যায়


12
list=`ls -a R*`
echo $list

শেল স্ক্রিপ্টের অভ্যন্তরে, এই ইকো কমান্ডটি আরে দিয়ে শুরু হওয়া বর্তমান ডিরেক্টরি থেকে সমস্ত ফাইলকে তালিকাবদ্ধ করবে তবে একটি লাইনে। আমি কীভাবে প্রতিটি আইটেম এক লাইনে মুদ্রণ করতে পারি?

আমি একটি জেনেরিক কমান্ড সঙ্গে ঘটছে সব পরিস্থিতিতে প্রয়োজন ls, du, find -type -d, ইত্যাদি


6
সাধারণ দ্রষ্টব্য: ls দিয়ে এটি করবেন না, এটি কোনও অদ্ভুত ফাইলের নাম ভাঙবেএখানে দেখুন ।
টেরডন

উত্তর:


12

যদি কমান্ডের আউটপুটে একাধিক লাইন থাকে তবে প্রতিধ্বনিত হওয়ার পরে সেই নতুনলাইনগুলি সংরক্ষণ করার জন্য আপনার ভেরিয়েবলগুলি উদ্ধৃত করুন:

echo "$list"

অন্যথায়, শেলটি স্পেসে স্পেসে পরিবর্তনশীল সামগ্রীগুলি প্রসারিত ও বিভক্ত করবে (স্পেস, নিউলাইনস, ট্যাবগুলি) এবং সেগুলি হারিয়ে যাবে।


15

পরিবর্তে lsভেরিয়েবলের মধ্যে আউটপুট রাখার পরিবর্তে এবং echoএটির পরে, যা সমস্ত রঙ মুছে ফেলে, ব্যবহার করুন

ls -a1

থেকে man ls

       -1     list one file per line.  Avoid '\n' with -q or -b

আমি আপনাকে lsপ্রদর্শন ছাড়াই আউটপুট দিয়ে কিছু করার পরামর্শ দিচ্ছি না :)

উদাহরণস্বরূপ, forফাইলগুলির সাথে কিছু করার জন্য শেল গ্লোব এবং একটি লুপ ব্যবহার করুন ...

shopt -s dotglob                  # to include hidden files*

for i in R/*; do echo "$i"; done

* এই বর্তমান ডিরেক্টরী অন্তর্ভুক্ত করবে না .বা তার পিতা বা মাতা ..যদিও


1
আমি প্রতিস্থাপনের পরামর্শ দেব: এর echo "$i"সাথে printf "%s\n" "$i" (ফাইল নামটি "-" দিয়ে শুরু করা হলে এটি শ্বাসরোধ করবে না)। আসলে, বেশিরভাগ সময় echo somethingদিয়ে প্রতিস্থাপন করা উচিত printf "%s\n" "something"
অলিভিয়ার ডুলাক

2
@ অলিভিয়ারডুলাক এগুলি Rএখানেই শুরু হয় তবে সাধারণভাবে হ্যাঁ। তবুও স্ক্রিপ্টিংয়ের জন্যও, সর্বদা- পথগুলিতে অগ্রণী হওয়ার চেষ্টা করার ফলে সমস্যা দেখা দেয়: লোকেরা ধরে নেয় --, যা কেবলমাত্র কয়েকটি কমান্ডই সমর্থন করে, বিকল্পগুলির শেষ নির্দেশ করে। আমি দেখেছি find . [tests] -exec [cmd] -- {} \;যেখানে [cmd]সমর্থন করে না --। সেখানকার প্রতিটি পথই .যেভাবেই শুরু হয় ! কিন্তু যে প্রতিস্থাপন বিরুদ্ধে কোনো যুক্তি echoদিয়ে printf '%s\n'এখানে, এক সঙ্গে পুরো লুপ প্রতিস্থাপন করতে পারেন printf '%s\n' R/*। বাশের printfএকটি বিল্টিন হিসাবে রয়েছে , সুতরাং কার্যকরভাবে যুক্তির সংখ্যা / দৈর্ঘ্যের কোনও সীমা নেই।
এলিয়াহ কাগন

12

এটিকে @ মুরু হিসাবে উদ্ধৃতিতে রাখার সময় প্রস্তাবিত আপনি যা চেয়েছিলেন তা করবে, আপনি জন্য কোনও অ্যারে ব্যবহার করার বিষয়টিও বিবেচনা করতে পারেন। উদাহরণ স্বরূপ:

IFS=$'\n' dirs=( $(find . -type d) )

IFS=$'\n'ব্যাশ বলে শুধুমাত্র সম্পর্কে newline characcters ণ উপর আউটপুট বিভক্ত করতে অ্যারের প্রতিটি উপাদান পেতে। এটি ছাড়া এটি স্পেসে বিভক্ত হবে, সুতরাং এটির a file name with spaces.txtপরিবর্তে 5 টি পৃথক উপাদান হবে। আপনার ফাইল / ডিরেক্টরি নামগুলিতে নতুন লাইন থাকতে পারে তবে এই পদ্ধতিটি ভেঙে যাবে\n যদিও ) । এটি কমান্ডের আউটপুট প্রতিটি রেখাকে অ্যারের উপাদান হিসাবে সংরক্ষণ করবে ।

নোট করুন যে আমি পুরানো-স্টাইলটিও পরিবর্তন করেছি `command` করতে $(command)যা পছন্দের সিনট্যাক্স হয়।

আপনার এখন একটি অ্যারে বলা হয়েছে $dirs, প্রতিটি বোফ যার উপাদানগুলি পূর্ববর্তী কমান্ডের আউটপুটের একটি লাইন। উদাহরণ স্বরূপ:

$ find . -type d
.
./olad
./ho
./ha
./ads
./bar
./ga
./da
$ IFS=$'\n' dirs=( $(find . -type d) )
$ for d in "${dirs[@]}"; do
    echo "DIR: $d"
  done
DIR: .
DIR: ./olad
DIR: ./ho
DIR: ./ha
DIR: ./ads
DIR: ./bar
DIR: ./ga
DIR: ./da

এখন, কিছু বাশ অদ্ভুততার কারণে ( এখানে দেখুন) ), আপনাকে IFSএটি করার পরে আবার মূল পুনরায় সেট করতে হবে । সুতরাং, হয় এটি সংরক্ষণ করুন এবং পুনরায় সাইন ইন করুন:

oldIFS="$IFS"
IFS=$'\n' dirs=( $(find . -type d) ) 
IFS="$oldIFS"

অথবা এটি নিজেই করুন:

IFS=" "$'\t\n '

বিকল্পভাবে, কেবলমাত্র বর্তমান টার্মিনালটি বন্ধ করুন। আপনার নতুনটিতে আবার আসল আইএফএস সেট থাকবে।


আমি duএটির মতো কিছু প্রস্তাব দিতে পারি, তবে তারপরে অংশটি এটিকে দেখায় ওপুট ফর্ম্যাটটি সংরক্ষণে আরও আগ্রহী।
মুড়ু

ডিরেক্টরিগুলির নামের ফাঁকে ফাঁকে থাকলে আমি কীভাবে এই কাজটি করতে পারি?
মিষ্টান্ন

হুফ! এটি এখন স্পেসগুলির সাথে কাজ করা উচিত (তবে নতুন লাইন নয়)। এটা ইশারা জন্য ধন্যবাদ।
টেরডন

1
নোট করুন যে আপনার অ্যারে অ্যাসাইনমেন্টের পরে আইএফএস পুনরায় সেট করতে বা আনসেট করা উচিত। unix.stackexchange.com/q/264635/70524
muru

@ মুরু ওহ, ধন্যবাদ, আমি সেই অদ্ভুততার কথা ভুলে গেছি।
টেরডন

2

যদি আপনাকে অবশ্যই আউটপুট সংরক্ষণ করতে হয় এবং আপনি কোনও অ্যারে চান তবে mapfileএটি সহজ করে তোলে।

প্রথমে বিবেচনা করুন আপনি যদি আপনার কমান্ডের আউটপুটটি আদৌ সঞ্চয় হবেআপনি যদি না করেন তবে কমান্ডটি চালান।

আপনি যদি সিদ্ধান্ত নেন যে আপনি কোনও কমান্ডের আউটপুটকে লাইনের অ্যারে হিসাবে পড়তে চান তবে এটি সত্য যে এটি করার একটি উপায় হ'ল গ্লোব্বিং নিষ্ক্রিয় করা, IFSলাইনগুলিতে বিভক্ত হওয়া, ( )অ্যারে তৈরির বাক্য গঠনের অভ্যন্তরে কমান্ড প্রতিস্থাপন ব্যবহার করা এবং IFSতারপরে পুনরায় সেট করা, যা মনে হয় তার চেয়ে জটিলটেরডনের উত্তর সেই পদ্ধতির কিছুটি জুড়ে। তবে আমি আপনাকে পরামর্শ দিচ্ছি যে পরিবর্তে পাঠ্যগুলি লাইনের অ্যারে হিসাবে পড়ার জন্য mapfileবাশ শেলের বিল্ট ইন কমান্ডটি ব্যবহার করুন। এখানে একটি সরল কেস রয়েছে যেখানে আপনি ফাইল থেকে পড়ছেন:

mapfile < filename

এটি লাইনগুলিকে অ্যারেতে পাঠায় MAPFILEইনপুট পুনঃনির্দেশ ছাড়াই আপনি শেলটির স্ট্যান্ডার্ড ইনপুট (সাধারণত আপনার টার্মিনাল) দ্বারা নামকৃত ফাইলটির পরিবর্তে পড়বেন । ডিফল্ট ব্যতীত অন্য কোনও অ্যারেতে পড়তে এর নামটি দিন। উদাহরণস্বরূপ, এটি অ্যারেতে পড়ে :< filenamefilenameMAPFILElines

mapfile lines < filename

আপনি যে ডিফল্ট আচরণ পরিবর্তন করতে বেছে নিতে পারেন তা হ'ল লাইনের শেষ প্রান্তে থাকা নিউলাইন অক্ষরগুলি সেখানে রেখে দেওয়া হয়েছে; এগুলি প্রতিটি অ্যারের উপাদানটিতে সর্বশেষ অক্ষর হিসাবে উপস্থিত হয় (যদি না কোনও নিউলাইন অক্ষর ব্যতীত ইনপুটটি শেষ না হয়, যার ক্ষেত্রে শেষ উপাদানটির একটি না থাকে)। এই নিউলাইনগুলি চম্প করতে যাতে তারা অ্যারেটিতে উপস্থিত না হয়, -tবিকল্পটি পাস করুন mapfile। উদাহরণস্বরূপ, এটি অ্যারে পড়ে recordsএবং এর অ্যারে উপাদানগুলিতে নতুন লাইনের অক্ষরগুলি লিখে না:

mapfile -t records < filename

আপনি -tঅ্যারের নামটি না দিয়েও ব্যবহার করতে পারেন ; এটি, এর একটি অন্তর্নিবিষ্ট অ্যারে নামের MAPFILEসাথেও কাজ করে।

mapfileশেল সমর্থন builtin অন্যান্য অপশন, এবং এটি অন্যথায় যেমন প্রার্থনা করা যেতে পারে readarray। বিশদ জন্য চালান help mapfile(এবং help readarray)।

তবে আপনি কোনও ফাইল থেকে পড়তে চান না, আপনি একটি কমান্ডের আউটপুট থেকে পড়তে চান। এটি অর্জন করতে, প্রক্রিয়া বিকল্প ব্যবহার করুন । এই কমান্ডের সার্চ হুকুম থেকে লাইন some-commandদিয়ে arguments...তার কমান্ড লাইন আর্গুমেন্ট এবং তাদের মধ্যে স্থানগুলির mapfileএর ডিফল্ট বিন্যাস MAPFILE, তাদের সসীম সম্পর্কে newline অক্ষর সরানো হয়েছে:

mapfile -t < <(some-command arguments...)

প্রক্রিয়া প্রতিস্থাপনটি একটি আসল ফাইলনামের সাথে প্রতিস্থাপন করে যেখানে থেকে চালনার আউটপুটটি পড়া যায়। ফাইলটি একটি নিয়মিত ফাইলের পরিবর্তে একটি নামযুক্ত পাইপ এবং উবুন্টুতে এটির নাম দেওয়া হবে (কখনও কখনও অন্য কিছু সংখ্যার সাথেও রয়েছে ) তবে আপনাকে বিশদটি নিয়ে নিজেকে উদ্বিগ্ন হওয়ার দরকার নেই, কারণ শেলটি এটির যত্ন নেয় সব পর্দার পিছনে।<(some-command arguments...)some-command arguments.../dev/fd/6363

পরিবর্তে ব্যবহার করে আপনি বিকল্প প্রতিস্থাপনটি ভুলে যেতে পারেন বলে মনে করতে পারেন , তবে এটি কার্যকর হবে না কারণ যখন আপনার একাধিক কমান্ডের পাইপলাইন পৃথক করে আলাদা করা হয় , তখন ব্যাশ সাবশেলের সমস্ত কমান্ড চালায় । এইভাবে এবং উভয়ই তাদের নিজস্ব পরিবেশে চালিত হয় , আপনি যে পাইপলাইনটি চালান সেই শেলের পরিবেশ থেকে শুরু করে তবে পৃথক। সাবচেলে যেখানে সঞ্চালিত হয় সেখানে অ্যারেটি পপুলেশন হয় না , তবে কমান্ড শেষ হয়ে গেলে অ্যারেটি ফেলে দেওয়া হয়। কলারের জন্য কখনও তৈরি বা পরিবর্তিত হয় না।some-command arguments... | mapfile -t|some-command arguments...mapfile -tmapfile -tMAPFILEMAPFILE

এখানে কি উদাহরণ মধ্যে terdon এর উত্তর দেখে মনে হচ্ছে, সম্পূর্ণতা, যদি আপনি ব্যবহার mapfile:

mapfile -t dirs < <(find . -type d)
for d in "${dirs[@]}"; do
    echo "DIR: $d"
done

এটাই. আপনি প্রয়োজন হবে না যদি পরীক্ষা IFSহয় না তা হয় ট্র্যাক এবং কি মান রাখতে একটি newline এটি সেট, তারপর রিসেট করতে অথবা পুনরায় সেট না এটা পরে। আপনি নিষ্ক্রিয় করতে না globbing (উদাহরণস্বরূপ, সঙ্গে set -f) - যা সত্যিই প্রয়োজন হয়, আপনি গম্ভীরভাবে যে পদ্ধতি ব্যবহার যেহেতু ফাইলের নামের থাকতে পারে যদি *, ?এবং [এটা --then পুনরায়-সক্ষম (set +f ) পরে।

আপনি সেই নির্দিষ্ট লুপটিকে পুরোপুরি একটি একক printfকমান্ডের সাথেও প্রতিস্থাপন করতে পারেন - যদিও এটি আসলে কোনও উপকার নয় mapfile, আপনি mapfileঅ্যারেটি তৈরি করতে অন্য কোনও পদ্ধতি ব্যবহার করেন কিনা তা করতে পারেন । এখানে একটি সংক্ষিপ্ত সংস্করণ:

mapfile -t < <(find . -type d)
printf 'DIR: %s\n' "${MAPFILE[@]}"

এটি মনে রাখা জরুরী যে, টেরডন যেমন উল্লেখ করেছেন , লাইন বাই লাইন অপারেটিং সর্বদা যথাযথ নয় এবং নতুন লাইনে থাকা ফাইল নামগুলির সাথে সঠিকভাবে কাজ করবে না। আমি সেইভাবে ফাইলগুলির নামকরণের বিরুদ্ধে প্রস্তাব দিই, তবে তা পারে দৃর্ঘটনায় সহ ঘটে।

আসলেই এক-আকারের-ফিট-সব সমাধান নেই।

আপনি "সমস্ত পরিস্থিতিতে একটি জেনেরিক কমান্ড" এবং ব্যবহারের পদ্ধতির জন্য জিজ্ঞাসা করেছিলেন mapfile লক্ষ্যে কিছুটা পদ্ধতির পদ্ধতির জন্য বলেছেন, তবে আমি আপনাকে অনুরোধ করছি আপনার প্রয়োজনীয়তাগুলি নিয়ে পুনর্বিবেচনা করার জন্য।

উপরে প্রদর্শিত টাস্কটি কেবলমাত্র একটি একক findকমান্ড দিয়ে আরও ভালভাবে অর্জন করা যেতে পারে :

find . -type d -printf 'DIR: %p\n'

আপনি প্রতিটি লাইনের শুরুতে sedযুক্ত DIR: করতে একটি বাহ্যিক কমান্ডও ব্যবহার করতে পারেন । এটি তর্কসাপেক্ষভাবে কিছুটা কুৎসিত এবং এটির আদেশের বিপরীতে এটি ফাইললাইমগুলিতে নতুন লাইন যুক্ত অতিরিক্ত "উপসর্গ" যুক্ত করবে, তবে এটির ইনপুট নির্বিশেষে এটি কাজ করে যাতে এটি আপনার প্রয়োজন অনুসারে বাছাই করে এবং এটি আউটপুটটি আউটপুট পড়ার পক্ষে আরও ভাল is পরিবর্তনশীল বা অ্যারে :

find . -type d | sed 's/^/DIR: /'

যদি আপনাকে প্রতিটি ডিরেক্টরিতে তালিকা তৈরি করতে এবং পাওয়া যায় যেমন some-commandযেমন একটি আর্গুমেন্ট হিসাবে ডিরেক্টরিটির পথ চালানো এবং পাস করা, তবে findআপনাকে এটি করতে দেয়:

find . -type d -print -exec some-command {} \;

অন্য উদাহরণ হিসাবে, আসুন প্রতিটি লাইনে একটি উপসর্গ যোগ করার সাধারণ কার্যে ফিরে আসি। ধরুন আমি আউটপুট দেখতে চাই help mapfileতবে লাইনগুলিকে সংখ্যায়িত করব। আমি আসলে mapfileএটির জন্য ব্যবহার করব না বা অন্য কোনও পদ্ধতি যা এটিকে শেল ভেরিয়েবল বা শেল অ্যারে পড়বে। ধরুন help mapfile | cat -nআমি যে ফর্ম্যাট করতে চাই তা দেয় না, আমি এটি ব্যবহার করতে পারি awk:

help mapfile | awk '{ printf "%3d: %s\n", NR, $0 }'

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

একটি বিকল্প যা সাধারণত চেষ্টা করা হয় - এবং কখনও কখনও ঠিক করা হয় - read -rলুপের সাহায্যে ইনপুট লাইন বাই লাইনে পড়া । পরবর্তী লাইনে অপারেটিং করার সময় যদি আপনার পূর্ববর্তী লাইনগুলি সংরক্ষণ করার প্রয়োজন না হয় এবং আপনাকে দীর্ঘ ইনপুট ব্যবহার করতে হয়, তবে এটি এর চেয়ে ভাল হতে পারে mapfile। তবে এটির ক্ষেত্রেও এড়ানো উচিত যখন আপনি কেবল এটি কোনও কাজটি করতে পারে এমন কোনও আদেশের সাথে পাইপ করতে পারেন, যা বেশিরভাগ ক্ষেত্রে

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