শেল কমান্ডের আউটপুটে অক্ষরের সংখ্যা


12

আমি একটি স্ক্রিপ্ট লিখছি যা কমান্ডের আউটপুটে একক পদক্ষেপে অক্ষরের সংখ্যা গণনা করা দরকার ।

উদাহরণস্বরূপ, কমান্ডটি ব্যবহার করে readlink -f /etc/fstabফিরে আসা উচিত 10কারণ command কমান্ডটির আউটপুট 10 অক্ষর দীর্ঘ।

নিম্নলিখিত কোড ব্যবহার করে সঞ্চিত ভেরিয়েবলের মাধ্যমে এটি ইতিমধ্যে সম্ভব:

variable="somestring";
echo ${#variable};
# 10

দুর্ভাগ্যক্রমে, কমান্ড-উত্পাদিত স্ট্রিং সহ একই সূত্র ব্যবহার করা কার্যকর হয় না:

${#(readlink -f /etc/fstab)};
# bash: ${#(readlink -f /etc/fstab)}: bad substitution

আমি বুঝতে পেরেছি প্রথমে আউটপুটটিকে ভেরিয়েবলে সংরক্ষণ করে এটি করা সম্ভব:

variable=$(readlink -f /etc/fstab);
echo ${#variable};

তবে আমি অতিরিক্ত পদক্ষেপটি সরাতে চাই।

এটা কি সম্ভব? শুধুমাত্র বিল্ট বা স্ট্যান্ডার্ড ইউটিলিটিগুলি ব্যবহার করে অ্যালামকুইস্ট শেল (শ) এর সাথে সামঞ্জস্যযোগ্যতা বঞ্চিত।


1
আউটপুট readlink -f /etc/fstabহয় 11 টি অক্ষর। নতুন লাইনটি ভুলে যাবেন না। অন্যথায় আপনি /etc/fstabluser@cern:~$ যখন এটি শেল থেকে দৌড়েছিলেন তখন আপনি দেখতে পাবেন ।
ফিল ফ্রস্ট

@ ফিলফ্রস্ট আপনার কাছে একটি মজার প্রম্পট বলে মনে হচ্ছে, আপনি কি সিইআরএন-এ কাজ করবেন?
দিমিত্রি গ্রিগরিয়েভ

উত্তর:


9

সঙ্গে গনুহ expr :

$ expr length + "$(readlink -f /etc/fstab)"
10

+নেই গনুহ একটি বিশেষ বৈশিষ্ট্য exprনিশ্চিত পরবর্তী যুক্তি string হিসাবে গণ্য হবে যদিও তা একটি হতে হবে করতে exprমত অপারেটর match, length, +...

উপরেরগুলি আউটপুটটির যেকোন পেছনের নতুন লাইনটি ছড়িয়ে দেবে। এটি চারপাশে কাজ করতে:

$ expr length + "$(readlink -f /etc/fstab; printf .)" - 2
10

ফলাফলটি 2 তে বিয়োগ করা হয়েছিল কারণ এর চূড়ান্ত নিউলাইন readlinkএবং .আমরা যে চরিত্রটি যুক্ত করেছি।

ইউনিকোড স্ট্রিং সহ, exprএটি কাজ করে বলে মনে হচ্ছে না কারণ এটি অক্ষর গণনার পরিবর্তে বাইটে স্ট্রিংয়ের দৈর্ঘ্য দেয় ( লাইন 654 দেখুন )

$ LC_ALL=C.UTF-8 expr length ăaa
4

সুতরাং, আপনি ব্যবহার করতে পারেন:

$ printf "ăaa" | LC_ALL=C.UTF-8 wc -m
3

POSIXLY:

$ expr " $(readlink -f /etc/fstab; printf .)" : ".*" - 3
10

কমান্ড প্রতিস্থাপনের আগে স্থানটি কমান্ডটিকে স্ট্রিং দিয়ে ক্র্যাশ হতে বাধা দেয় -, সুতরাং আমাদের 3 টি বিয়োগ করতে হবে।


ধন্যবাদ! দেখে মনে হচ্ছে আপনার তৃতীয় উদাহরণটি ব্যতীতও কাজ করে LC_ALL=C.UTF-8, যা স্ট্রিংয়ের এনকোডিং আগে থেকেই জানা না গেলে জিনিসগুলি উল্লেখযোগ্যভাবে সরল করে।
ব্যবহারকারী 339676

2
expr length $(echo "*")- না। অন্তত উদ্ধৃতি চিহ্ন ব্যবহার করুন: expr length "$(…)"। কিন্তু এই কমান্ড থেকে নতুন লাইনের পিছনে বিচ্ছিন্ন, এটি কমান্ড প্রতিস্থাপনের একটি অদম্য বৈশিষ্ট্য। (আপনি এটির চারপাশে কাজ করতে পারেন তবে উত্তরটি আরও জটিল হয়ে যায়))
গিলস 'অশুভ হওয়া বন্ধ করুন'

6

শেল বিল্টিনগুলির সাহায্যে এটি কীভাবে করা যায় তা নিশ্চিত নয় ( ন্নোক যদিও এটি রয়েছে ) তবে মানক সরঞ্জামগুলি সহায়তা করতে পারে:

  1. আপনি কোন wc -mঅক্ষর গণনা করতে পারেন তা ব্যবহার করতে পারেন । দুর্ভাগ্যক্রমে, এটি চূড়ান্ত নিউলাইনকেও গণনা করে তাই আপনাকে প্রথমে এড়াতে হবে:

    readlink -f /etc/fstab | tr -d '\n' | wc -m
  2. আপনি অবশ্যই ব্যবহার করতে পারেন awk

    readlink -f /etc/fstab | awk '{print length($0)}'
  3. বা পার্ল

    readlink -f /etc/fstab | perl -lne 'print length'

আপনি exprএকটি বিল্ট ইন মানে ? কোন শেল?
মাইক্রজারভ

5

আমি সাধারণত এটি করে:

$ echo -n "$variable" | wc -m
10

কমান্ডগুলি করতে আমি এটি এর মতো করে খাপ খাই:

$ echo -n "$(readlink -f /etc/fstab)" | wc -m
10

এই পদ্ধতিটি আপনি আপনার 2 টি পদক্ষেপে যা করছেন তার সমান, আমরা যদি তাদের একক একলাইনারে সংযুক্ত করি।


2
-mপরিবর্তে আপনার অবশ্যই ব্যবহার করা উচিত -c। ইউনিকোড অক্ষর সহ, আপনার পদ্ধতির ভাঙা হবে।
cuonglm

1
কেন সহজভাবে নয় readlink -f /etc/fstab | wc -m?
ফিল ফ্রস্ট

1
আপনি কেন এই পরিবর্তে অবিশ্বাস্য পদ্ধতিটি ব্যবহার করবেন ${#variable}? কমপক্ষে ডাবল কোট ব্যবহার করুন echo -n "$variable"তবে এটি এখনও ব্যর্থ হয় যদি উদাহরণস্বরূপ এর মান variableহয় -e। আপনি যখন এটি কমান্ড বিকল্পের সাথে সংমিশ্রণে ব্যবহার করেন, মনে রাখবেন যে পিছনে থাকা নতুন লাইনগুলি বন্ধ হয়ে গেছে।
গিলস 'অশুভ হওয়া বন্ধ করুন'

@ ফিলফ্রস্ট বি / সি আমি যা দেখিয়েছি তা অপ্টটি ইতিমধ্যে কী ভাবছে of এছাড়াও এটি যে কোনও সেমিডিএসের জন্য কাজ করে যা তার আগে যুদ্ধগুলির আগে সেটআপ থাকতে পারে এবং সেগুলির দৈর্ঘ্য আফ্রোডও চায়। এছাড়াও টেরডনের ইতিমধ্যে উদাহরণ রয়েছে।
slm

1

আপনি বাহ্যিক ইউটিলিটিগুলিতে কল করতে পারেন (অন্যান্য উত্তর দেখুন), তবে তারা আপনার স্ক্রিপ্টটি ধীর করে দেবে এবং নদীর গভীরতানির্ণয়টি সঠিকভাবে পাওয়া শক্ত।

Zsh

Zsh এ, আপনি ${#$(readlink -f /etc/fstab)}কমান্ড প্রতিস্থাপনের দৈর্ঘ্য পেতে লিখতে পারেন । লক্ষ্য করুন যে এটি কমান্ড আউটপুটটির দৈর্ঘ্য নয়, এটি কোনও পূর্ববর্তী নিউলাইন ছাড়াই আউটপুটটির দৈর্ঘ্য।

আপনি যদি আউটপুটটির সঠিক দৈর্ঘ্য চান তবে শেষে একটি অতিরিক্ত নন-লাইন অক্ষর আউটপুট করুন এবং একটিটি বিয়োগ করুন।

$((${#$(readlink -f /etc/fstab; echo .)} - 1))

আপনি যা চান তা কমান্ডের আউটপুটে পে-লোড হয়, তবে আপনাকে এখানে দুটি বিয়োগ করতে হবে , কারণ আউটপুটটি readlink -fহ'ল ক্যানোনিকাল পাথ এবং একটি নতুন লাইন।

$((${#$(readlink -f /etc/fstab; echo .)} - 2))

এটি ${#$(readlink -f /etc/fstab)}বিরল তবে সম্ভাব্য ক্ষেত্রে থেকে আলাদা যেখানে প্রামাণিক পথটি একটি নতুন লাইনে শেষ হয়।

এই নির্দিষ্ট উদাহরণের জন্য, আপনার কোনও বাহ্যিক ইউটিলিটি দরকার নেই, কারণ zsh এর একটি বিল্ট-ইন কন্সট্রাক্ট রয়েছে যা readlink -fইতিহাস সংশোধকটির মাধ্যমে সমতুল্য A

echo /etc/fstab(:A)

দৈর্ঘ্য পেতে, প্যারামিটার প্রসারণে ইতিহাসের সংশোধক ব্যবহার করুন:

${#${:-/etc/fstab}:A}

আপনার যদি ভেরিয়েবলের ফাইলের নাম থাকে তবে filenameতা হবে ${#filename:A}

বোর্ন / পসিক্স-স্টাইল শেল

খাঁটি বোর্ন / পসিক্স শেলগুলির কোনওটিই (বোর্ন, অ্যাশ, ম্যাক্স, ksh93, বাশ, যশ ...) এর সাথে আমার পরিচিত কোনও মিল নেই। আপনার যদি কমান্ড প্রতিস্থাপনের আউটপুটে বা নীড় প্যারামিটার বিকল্পগুলির জন্য প্যারামিটার বিকল্প প্রয়োগ করতে হয় তবে ধারাবাহিক পর্যায়ে ব্যবহার করুন।

আপনি যদি চান তবে একটি প্রক্রিয়াতে প্রসেসিং স্টাফ করতে পারেন।

command_output_length_sans_trailing_newlines () {
  set -- "$("$@")"
  echo "${#1}"
}

অথবা

command_output_length () {
  set -- "$("$@"; echo .)"
  echo "$((${#1} - 1))"
}

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

আবার, এর আউটপুট readlink -fহ'ল ক্যানোনিকাল পাথ প্লাস একটি নতুন লাইন; আপনি যদি ক্যানোনিকাল পাথের দৈর্ঘ্য চান তবে 1 ইন এর পরিবর্তে 2 বিয়োগ করুন command_output_lengthcommand_output_length_sans_trailing_newlinesক্যানোনিকাল পথটি কোনও নতুন লাইনে শেষ না হলেই ব্যবহার সঠিক ফলাফল দেয়।

বাইটস বনাম অক্ষর

${#…}বাইটে নয়, অক্ষরগুলির দৈর্ঘ্য বলে মনে করা হয় যা মাল্টিবাইট লোকালগুলিতে পার্থক্য করে। যুক্তিসঙ্গতভাবে ksh93, বাশ এবং zsh এর আপ-টু-ডেট সংস্করণগুলি নির্মাণের সময় বাড়ানোর LC_CTYPEসময় অনুযায়ী মান অনুসারে দৈর্ঘ্যের দৈর্ঘ্য গণনা করে ${#…}। অন্যান্য অনেকগুলি সাধারণ শেল সত্যিকার অর্থে মাল্টিবাইট লোকেলগুলি সমর্থন করে না: ড্যাশ 0.5.7, ম্যাক্স 46 এবং পশ 0.12.3 হিসাবে, ${#…}দৈর্ঘ্য বাইটে দেয়। আপনি যদি নির্ভরযোগ্য উপায়ে অক্ষরগুলির দৈর্ঘ্য চান তবে wcইউটিলিটিটি ব্যবহার করুন :

$(readlink -f /etc/fstab | wc -m)

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

আপনি যদি দৈর্ঘ্য বাইটে চান, LC_CTYPE=Cঅস্থায়ীভাবে সেট করুন বা এর wc -cপরিবর্তে ব্যবহার করুন wc -m

বাইট বা অক্ষর সহ গণনা wcকরাতে কমান্ড থেকে আসা কোনও নতুন লাইনের অন্তর্ভুক্ত রয়েছে। আপনি যদি বাইটগুলিতে ক্যানোনিকাল পাথের দৈর্ঘ্য চান তবে এটি

$(($(readlink -f /etc/fstab | wc -c) - 1))

এটি অক্ষরে পেতে, 2 বিয়োগ করুন।


@ কুওগলম না, আপনাকে ১ টি বিয়োগ করতে হবে echo .দুটি অক্ষর যুক্ত করা হয়েছে, তবে দ্বিতীয় চরিত্রটি একটি অনুবর্তনযোগ্য নিউলাইন যা কমান্ড প্রতিস্থাপনের দ্বারা ছিনিয়ে নেওয়া হয়েছে।
গিলস 'অশুভ হওয়া বন্ধ করুন'

নতুন লাইনটি readlinkআউটপুট থেকে প্লাস .বাই echo। আমরা দুজনেই একমত যে echo .দু'টি অক্ষর যুক্ত করুন তবে পিছনের নতুন লাইনটি কেড়ে নেওয়া হয়েছিল। printf .আমার উত্তরটির সাথে চেষ্টা করুন বা দেখুন unix.stackexchange.com/a/160499/38906
cuonglm

@cuonglm প্রশ্নটি কমান্ডের আউটপুটে অক্ষরের সংখ্যা জিজ্ঞাসা করেছিল। এর আউটপুট readlinkহ'ল লিঙ্ক টার্গেট প্লাস একটি নতুন লাইন।
গিলস 'অশুভ হওয়া বন্ধ করুন'

0

এটি এতে কাজ করে dashতবে এটির জন্য লক্ষ্যবস্তুটি অবশ্যই খালি বা আনসেট করা দরকার। এজন্য এটি আসলে দুটি আদেশ - আমি $lপ্রথমটিতে স্পষ্টভাবে খালি :

l=;printf '%.slen is %d and result is %s\n' \
    "${l:=$(readlink -f /etc/fstab)}" "${#l}" "$l"

আউটপুট

len is 10 and result is /etc/fstab

এটি সমস্ত শেল বিল্টিনস - readlinkঅবশ্যই অন্তর্ভুক্ত নয় - তবে বর্তমান শেলটিতে এটির মূল্যায়ন হ'ল বোঝায় যে %.sলেনটি পাওয়ার আগে আপনাকে অবশ্যই অ্যাসাইনমেন্টটি করতে হবে, এজন্য আমি printfফর্ম্যাট স্ট্রিংয়ে প্রথম যুক্তিটি আইলেন্স করি এবং কেবল এটির জন্য আবার যুক্ত করব printfএর আর্গ তালিকার লেজটিতে আক্ষরিক মান ।

সহ eval:

l=$(readlink -f /etc/fstab) eval 'l=${#l}:$l'
printf %s\\n "$l"

আউটপুট

10:/etc/fstab

আপনি একই জিনিসটির কাছাকাছি যেতে পারেন, তবে প্রথম কমান্ডের একটি ভেরিয়েবলের আউটপুট পরিবর্তে আপনি স্টাডআউটে পাবেন:

PS4='${#0}:$0' dash -cx '2>&1' "$(readlink -f /etc/fstab)"

... যা লিখেছেন ...

10:/etc/fstab

... বর্তমান শেলের কোনও ভারের জন্য কোনও মান নির্ধারণ না করে বর্ণনাকারী 1 ফাইল করা।


1
ওপ কি ঠিক এড়াতে চেয়েছিল? "আমি বুঝতে পেরেছি প্রথমে আউটপুটটি ভেরিয়েবলে সংরক্ষণ করে এটি করা সম্ভব: variable=$(readlink -f /etc/fstab); echo ${#variable};তবে আমি অতিরিক্ত পদক্ষেপটি সরিয়ে ফেলতে চাই" "
টেরডন

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

1
evalভাবে, উপায় দ্বারা, সম্ভবত এখানে পরিষ্কার হয় - - এটি আউটপুট এবং একটি একক সঞ্চালনের একই Var নামের লেন নির্ধারণ খুব করছেন পাসে l=length(l):out(l)। এরকম expr length $(command) করে লেন পক্ষে মান অন্তর্ধারণ, উপায় দ্বারা।
মাইক্রজারভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.