$ * এবং $ @ এর মধ্যে পার্থক্য কী?


72

নিম্নলিখিত কোড বিবেচনা করুন:

foo () {
    echo $*
}

bar () {
    echo $@
}

foo 1 2 3 4
bar 1 2 3 4

এটি ফলাফল:

1 2 3 4

1 2 3 4

আমি Ksh88 ব্যবহার করছি তবে আমি অন্যান্য সাধারণ শেলগুলিতেও আগ্রহী। নির্দিষ্ট শাঁসের জন্য যদি আপনার কোনও বৈশিষ্ট্য জানা থাকে তবে দয়া করে সেগুলি উল্লেখ করুন।

আমি সোলারিসে Ksh ম্যান পেজে ফোলিং পেয়েছি:

$ * এবং $ @ এর অর্থটি একই রকম যখন উদ্ধৃতি না দেওয়া হয় বা যখন প্যারামিটার অ্যাসাইনমেন্ট মান হিসাবে বা কোনও ফাইলের নাম হিসাবে ব্যবহৃত হয়। তবে, যখন কমান্ড আর্গুমেন্ট হিসাবে ব্যবহৃত হয়, তখন $ * `$ 1d $ 2d ... '' এর সমান, যেখানে d আইএফএস ভেরিয়েবলের প্রথম অক্ষর, যেখানে $ @ $ 1 $ 2 .... এর সমান হয় ....

আমি IFSভেরিয়েবলটি সংশোধন করার চেষ্টা করেছি , তবে এটি আউটপুট পরিবর্তন করে না। আমি কি কিছু ভুল করছি?

উত্তর:


95

যখন এগুলি উদ্ধৃত করা হয় না $*এবং $@একই হয়। আপনার এগুলির কোনওটি ব্যবহার করা উচিত নয়, কারণ স্পেস বা ওয়াইল্ডকার্ড যুক্তি যুক্ত হওয়ার সাথে সাথে এগুলি অপ্রত্যাশিতভাবে ভেঙে যেতে পারে।


"$*"এককথায় প্রসারিত হয় "$1c$2c..."। সাধারণত cএকটি স্থান হয়, তবে এটি আসলে প্রথম চরিত্রের IFS, তাই এটি আপনার চয়ন করা কিছু হতে পারে।

আমি এর জন্য কেবলমাত্র ভাল ব্যবহারটি খুঁজে পেয়েছি:

কমা দিয়ে সাধারণ যুক্তিতে যোগ দিন (সাধারণ সংস্করণ)

join1() {
    typeset IFS=,
    echo "$*"
}

join1 a b c   # => a,b,c

নির্দিষ্ট ডিলিমিটারের সাথে যুক্তিতে যুক্ত হন (আরও ভাল সংস্করণ)

join2() {
    typeset IFS=$1   # typeset makes a local variable in ksh (see footnote)
    shift
    echo "$*"
}

join2 + a b c   # => a+b+c

"$@" পৃথক শব্দ প্রসারিত: "$1" "$2" ...

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


এর সাথে svimচলমান একটি স্ক্রিপ্ট লিখি । পার্থক্যটি চিত্রিত করার জন্য আমরা তিনটি সংস্করণ করব।vimsudo

svim1

#!/bin/sh
sudo vim $*

svim2

#!/bin/sh
sudo vim "$*"

svim3

#!/bin/sh
sudo vim "$@"

এগুলির সবগুলিই সাধারণ কেসগুলির জন্য সূক্ষ্ম হবে, উদাহরণস্বরূপ এমন একক ফাইলের নাম যাতে স্পেস থাকে না:

svim1 foo.txt             # == sudo vim foo.txt
svim2 foo.txt             # == sudo vim "foo.txt"
svim2 foo.txt             # == sudo vim "foo.txt"

তবে শুধুমাত্র $*এবং "$@"আপনার একাধিক যুক্তি থাকলে সঠিকভাবে কাজ করুন।

svim1 foo.txt bar.txt     # == sudo vim foo.txt bar.txt
svim2 foo.txt bar.txt     # == sudo vim "foo.txt bar.txt"   # one file name!
svim3 foo.txt bar.txt     # == sudo vim "foo.txt" "bar.txt"

এবং শুধুমাত্র "$*"এবং "$@"আপনার কাছে ফাঁকা স্থান যুক্তি থাকলে সঠিকভাবে কাজ করুন।

svim1 "shopping list.txt" # == sudo vim shopping list.txt   # two file names!
svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
svim3 "shopping list.txt" # == sudo vim "shopping list.txt"

তাই কেবল "$@"সর্বদা সঠিকভাবে কাজ করবে।


typesetকীভাবে স্থানীয় পরিবর্তনশীল করা যায় ksh( bashএবং পরিবর্তে ashব্যবহার localকরুন)। এর অর্থ IFSযখন ফাংশনটি ফিরে আসবে তখন এর আগের মানটিতে পুনরুদ্ধার করা হবে। এটি গুরুত্বপূর্ণ, কারণ আপনি যে আদেশগুলি পরে চালাচ্ছেন সেটি মানহীন IFSকিছুতে সেট করা থাকলে সঠিকভাবে কাজ করতে পারে না ।


2
অপূর্ব ব্যাখ্যা, আপনাকে অনেক ধন্যবাদ।
রাহমু

ব্যবহারের একটি উদাহরণের জন্য আপনাকে ধন্যবাদ $*। আমি সর্বদা এটি একেবারে অকেজো বলে বিবেচনা করছিলাম ... ডিলিমিটারের সাথে যোগ দেওয়া ভাল ব্যবহারের ক্ষেত্রে।
আনিসনে

35

সংক্ষিপ্ত উত্তর: ব্যবহার"$@" (ডাবল উদ্ধৃতি নোট) অন্যান্য ফর্ম খুব কমই দরকারী।

"$@"একটি বরং অদ্ভুত বাক্য গঠন। এটি পৃথক ক্ষেত্র হিসাবে সমস্ত অবস্থানগত পরামিতি দ্বারা প্রতিস্থাপিত হয়। যদি কোনও অবস্থানীয় প্যারামিটার না থাকে ( $#তবে 0 হয়) তবে "$@"কিছুতেই প্রসারিত হয় না (খালি স্ট্রিং নয়, তবে 0 টি উপাদান সহ একটি তালিকা), যদি একটি অবস্থানগত পরামিতি থাকে তবে "$@"সমান হয় "$1", যদি দুটি অবস্থানগত পরামিতি থাকে তবে "$@"তার সমান হয় "$1" "$2"ইত্যাদি

"$@"আপনাকে কোনও স্ক্রিপ্টের তর্ক বা অন্য কমান্ডে ফাংশন দেওয়ার অনুমতি দেয়। এটি র্যাপারগুলির জন্য খুব দরকারী যেগুলি পরিবেশের ভেরিয়েবলগুলি সেট করা, ডেটা ফাইল প্রস্তুত করা ইত্যাদির মতো জিনিসগুলি করে যা একইভাবে যুক্তি এবং বিকল্পগুলির সাহায্যে র‌্যাপারটি কল করা হয়েছিল calling

উদাহরণস্বরূপ, নিম্নলিখিত ফাংশন এর আউটপুট ফিল্টার করে cvs -nq update। আউটপুট ফিল্টারিং এবং রিটার্নের স্থিতি (যা তার grepচেয়ে বরং এটি হয় cvs) ব্যতীত cvssmকিছু যুক্তিযুক্ত কলগুলি cvs -nq updateএই যুক্তিগুলির সাথে কল করার মতো আচরণ করে ।

cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }

"$@"অবস্থানগত পরামিতিগুলির তালিকায় প্রসারিত হয়। অ্যারেগুলিকে সমর্থন করে এমন শেলগুলিতে অ্যারের উপাদানগুলির তালিকায় প্রসারিত করার জন্য অনুরূপ বাক্য গঠন রয়েছে: "${array[@]}"(ধনুর্বন্ধনী zsh ব্যতীত বাধ্যতামূলক)। আবার, ডাবল উদ্ধৃতিগুলি কিছুটা বিভ্রান্তিকর: তারা ক্ষেত্র বিভাজন এবং অ্যারের উপাদানগুলির প্যাটার্ন জেনারেশন থেকে সুরক্ষা দেয় তবে প্রতিটি অ্যারে উপাদান তার নিজস্ব ক্ষেত্রে শেষ হয়।

কিছু প্রাচীন শেলের মধ্যে ত্রুটিযুক্ত ত্রুটি ছিল: যখন কোনও অবস্থানগত যুক্তি ছিল না, "$@"কোনও ক্ষেত্রের পরিবর্তে খালি স্ট্রিং সম্বলিত একক ক্ষেত্রে প্রসারিত হয়েছিল। এটি কার্যবিধির${1+"$@"} দিকে নিয়ে গেল ( পার্ল ডকুমেন্টেশনের মাধ্যমে বিখ্যাত হয়েছে )। কেবল আসল বোর্ন শেল এবং ওএসএফ 1 বাস্তবায়নের শুধুমাত্র পুরানো সংস্করণগুলি প্রভাবিত হয়েছে, এর আধুনিক সামঞ্জস্যপূর্ণ প্রতিস্থাপনগুলির (অ্যাশ, কেএসএইচ, বাশ,…) কোনওটিই নয়। /bin/shআমি জানি যে 21 তম শতাব্দীতে মুক্তি পেয়েছে এমন কোনও সিস্টেমে প্রভাবিত হবে না (যদি আপনি Tru64 রক্ষণাবেক্ষণের রিলিজ গণনা করেন না, এবং এমনকি /usr/xpg4/bin/shনিরাপদ থাকেন তবে কেবল #!/bin/shস্ক্রিপ্টই ক্ষতিগ্রস্থ হয় না, #!/usr/bin/env shযতক্ষণ না আপনার PATH প্যাসিক্স সম্মতিতে সেট করা থাকে ততক্ষণ স্ক্রিপ্টগুলি নয় ) । সংক্ষেপে, এটি একটি historicalতিহাসিক উপাখ্যান যা আপনাকে উদ্বিগ্ন হওয়ার দরকার নেই।


"$*"সর্বদা এক কথায় প্রসারিত হয়। এই শব্দটির মধ্যে অবস্থানগত পরামিতি রয়েছে, এর মাঝখানে একটি স্থান দিয়ে সংমিশ্রিত হয়। (আরও সাধারণভাবে, বিভাজকটি IFSভেরিয়েবলের মানের প্রথম অক্ষর হয় If যদি মানটি IFSখালি স্ট্রিং হয় তবে বিভাজকটি খালি স্ট্রিং)) যদি কোনও অবস্থানগত পরামিতি না থাকে তবে "$*"খালি স্ট্রিংটি থাকে, যদি দুটি থাকে অবস্থানগত পরামিতি এবং IFSএর ডিফল্ট মান হয় তার "$*"সমান "$1 $2", ইত্যাদি etc.

$@এবং $*বাইরের উদ্ধৃতি সমান। এগুলি পৃথক ক্ষেত্রের মতো অবস্থানগত পরামিতিগুলির তালিকায় প্রসারিত হয় "$@"; তবে প্রতিটি ফলাফল ক্ষেত্র পৃথক ক্ষেত্রগুলিতে বিভক্ত হয় যা ফাইলের নাম ওয়াইল্ডকার্ড নিদর্শন হিসাবে বিবেচিত হয়, যথাযথভাবে অযোগ্য ভেরিয়েবল বিস্তারের সাথে।

উদাহরণস্বরূপ, যদি বর্তমান ডিরেক্টরী তিন ফাইল রয়েছে bar, bazএবং foo, তারপর:

set --         # no positional parameters
for x in "$@"; do echo "$x"; done  # prints nothing
for x in "$*"; do echo "$x"; done  # prints 1 empty line
for x in $*; do echo "$x"; done    # prints nothing
set -- "b* c*" "qux"
echo "$@"      # prints `b* c* qux`
echo "$*"      # prints `b* c* qux`
echo $*        # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done  # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done  # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done    # prints 4 lines: `bar`, `baz`, `c*` and `qux`

1
ঐতিহাসিক দ্রষ্টব্য: কিছু প্রাচীন বোর্ন শাঁস উপর, "$@": প্রকৃতপক্ষে খালি স্ট্রিং একটি তালিকা consisiting প্রসারিত হয়নি unix.stackexchange.com/questions/68484/...
ninjalj

25

$*এবং এর মধ্যে পার্থক্যটি দেখানোর জন্য এখানে একটি সাধারণ স্ক্রিপ্ট রয়েছে $@:

#!/bin/bash

test_param() {
  echo "Receive $# parameters"
  echo Using '$*'

  echo
  for param in $*; do
    printf '==>%s<==\n' "$param"
  done;

  echo
  echo Using '"$*"'
  for param in "$*"; do
    printf '==>%s<==\n' "$param"
  done;

  echo
  echo Using '$@'
  for param in $@; do
    printf '==>%s<==\n' "$param"
  done;

  echo
  echo Using '"$@"';
  for param in "$@"; do
  printf '==>%s<==\n' "$param"
  done
}

IFS="^${IFS}"

test_param 1 2 3 "a b c"

আউটপুট:

% cuonglm at ~
% bash test.sh
Receive 4 parameters

Using $*
==>1<==
==>2<==
==>3<==
==>a<==
==>b<==
==>c<==

Using "$*"
==>1^2^3^a b c<==

Using $@
==>1<==
==>2<==
==>3<==
==>a<==
==>b<==
==>c<==

Using "$@"
==>1<==
==>2<==
==>3<==
==>a b c<==

অ্যারে সিনট্যাক্সে, ব্যবহার করার সময় $*বা কোনও পার্থক্য নেই $@। আপনি কেবল ডাবল উদ্ধৃতি "$*"এবং ব্যবহার করে এগুলি কেবল তখনই বোধগম্য হয় "$@"


দুর্দান্ত উদাহরণ! আপনি এর ব্যবহার ব্যাখ্যা করতে পারেন IFS="^${IFS}", যদিও?
রাশ

@ রুস: এটি আপনাকে দেখায় যে প্রথম অক্ষরের সাথে মানটি কীভাবে সমৃদ্ধ IFS
cuonglm

একইভাবে যে IFS="^xxxxx"কি হবে? পেছনের ${IFS}প্রত্যয়টি আমাকে ভাবিয়ে তোলে যে আপনি কিছুটা কৌতুকপূর্ণ কাজ করছেন, যেমন শেষের দিকে কোনওভাবে স্বয়ংক্রিয়ভাবে মূল আইএফএস পুনরুদ্ধার করা (যেমন: প্রথম চরটি স্বয়ংক্রিয়ভাবে স্থানান্তরিত হয়ে গেছে বা কিছু)।
রাশ

11

আপনার প্রদত্ত কোডটি একই ফল দেবে। এটি আরও ভালভাবে বুঝতে, এটি ব্যবহার করে দেখুন:

foo () {
    for i in "$*"; do
        echo "$i"
    done
}

bar () {
    for i in "$@"; do
        echo "$i"
    done
}

আউটপুট এখন আলাদা হওয়া উচিত। আমি যা পাই তা এখানে:

$ foo() 1 2 3 4
1 2 3 4
$ bar() 1 2 3 4
1
2
3
4

এটি আমার পক্ষে কাজ করেছে bash। যতদূর আমি জানি, ksh এর চেয়ে বেশি পার্থক্য করা উচিত নয়। মূলত, উদ্ধৃতি $*সমস্ত কিছুকে একটি শব্দ হিসাবে বিবেচনা করবে এবং উদ্ধৃতি $@তালিকাটিকে পৃথক শব্দ হিসাবে বিবেচনা করবে, যেমন উপরের উদাহরণে দেখা যাবে।

এর IFSসাথে ভেরিয়েবল ব্যবহারের উদাহরণ হিসাবে এটি $*বিবেচনা করুন

fooifs () {
    IFS="c"            
    for i in "$*"; do
        echo "$i"
    done
    unset IFS          # reset to the original value
}

আমি ফলাফল হিসাবে এটি পেতে:

$ fooifs 1 2 3 4
1c2c3c4

এছাড়াও, আমি ঠিক নিশ্চিত করেছি যে এটি একইভাবে কাজ করে ksh। এখানে bashএবং kshপরীক্ষিত উভয়ই ওএসএক্সের অধীনে ছিল তবে কীভাবে এটি বেশি গুরুত্বপূর্ণ তা আমি দেখতে পাচ্ছি না।


"একটি ফাংশনের মধ্যে পরিবর্তিত হয়েছে - গ্লোবালকে প্রভাবিত করে না"। তুমি কি পরীক্ষা করেছ?
মাইকেল

হ্যাঁ, আমি এটি পরীক্ষা করেছি। মনের প্রশান্তির জন্য, আমি এটিকে মূলটিতে unset IFSপুনরায় সেট করতে শেষ পর্যন্ত যুক্ত করব , তবে এটি আমার পক্ষে কোনও সমস্যা না করে এবং echo $IFSএটি থেকে প্রাপ্ত স্ট্যান্ডার্ড আউটপুটটির ফলস্বরূপ কাজ করে। IFSকোঁকড়া বন্ধনীর সাথে উইনিং সেট করা একটি নতুন সুযোগের পরিচয় দেয়, সুতরাং আপনি যদি এটি রফতানি না করেন তবে এটি বাইরের উপর প্রভাব ফেলবে না IFS
Wojtek Rzepala

echo $IFSকিছুই প্রমাণ করে না, কারণ শেলটি দেখতে পায় ,তবে শব্দটি ব্যবহার করে বিভক্ত হয়ে যায় IFS! ব্যবহার করে দেখুন echo "$IFS"
মাইকেল

ভাল যুক্তি. আনসেটিংয়ের IFSসমাধান করা উচিত।
Wojtek Rzepala

যদি না IFSফাংশন কল করার আগে বিভিন্ন কাস্টম মান ছিল। তবে হ্যাঁ, বেশিরভাগ সময় আনসেট করা আইএফএস কাজ করবে।
মাইকেল

6

স্ক্রিপ্টগুলি লেখার সময় পার্থক্যটি গুরুত্বপূর্ণ যা সঠিকভাবে অবস্থানগত পরামিতিগুলি ব্যবহার করা উচিত ...

নিম্নলিখিত কলটি কল্পনা করুন:

$ myuseradd -m -c "Carlos Campderrós" ccampderros

এখানে মাত্র 4 টি পরামিতি রয়েছে:

$1 => -m
$2 => -c
$3 => Carlos Campderrós
$4 => ccampderros

আমার ক্ষেত্রে এটি একই পরামিতি গ্রহণ করার myuseraddজন্য কেবল একটি মোড়ক useradd, তবে ব্যবহারকারীর জন্য একটি কোটা যুক্ত করে:

#!/bin/bash -e

useradd "$@"
setquota -u "${!#}" 10000 11000 1000 1100

উদ্ধৃত কল useradd "$@"সহ কল করুন $@। এটি প্যারামিটারগুলিকে সম্মান জানাবে এবং তাদের যেমন হয় তেমন পাঠাবে useradd। যদি আপনি উদ্ধৃত না $@হন (বা $*এছাড়াও অব্যক্ত ব্যবহারের জন্য), ইউর্যাডড 5 টি প্যারামিটার দেখতে পাবে , তৃতীয় প্যারামিটারে একটি স্পেস রয়েছে এমন দুটি বিভক্ত হবে:

$1 => -m
$2 => -c
$3 => Carlos
$4 => Campderrós
$5 => ccampderros

(এবং বিপরীতে, আপনি যদি ব্যবহার করতে চান তবে "$*"ইউজারডেড কেবল একটি প্যারামিটার দেখতে পাবে -m -c Carlos Campderrós ccampderros:)

সুতরাং, সংক্ষেপে, আপনার যদি মাল্টি-ওয়ার্ড পরামিতিগুলির সম্মান করে প্যারামিটারগুলির সাথে কাজ করতে হয় তবে ব্যবহার করুন "$@"


4
   *      Expands  to  the positional parameters, starting from one.  When
          the expansion occurs within double quotes, it expands to a  sin
          gle word with the value of each parameter separated by the first
          character of the IFS special variable.  That is, "$*" is equiva
          lent to "$1c$2c...", where c is the first character of the value
          of the IFS variable.  If IFS is unset, the parameters are  sepa
          rated  by  spaces.   If  IFS  is null, the parameters are joined
          without intervening separators.
   @      Expands to the positional parameters, starting from  one.   When
          the  expansion  occurs  within  double  quotes,  each  parameter
          expands to a separate word.  That is, "$@" is equivalent to "$1"
          "$2"  ...   If the double-quoted expansion occurs within a word,
          the expansion of the first parameter is joined with  the  begin
          ning  part  of  the original word, and the expansion of the last
          parameter is joined with the last part  of  the  original  word.
          When  there  are no positional parameters, "$@" and $@ expand to
          nothing (i.e., they are removed).

// ম্যান বাশ । ksh, আফের, একইরকম আচরণ।


2

zshএবং এর মধ্যে পার্থক্য সম্পর্কে কথা বলা bash:

প্রায় কোট দিয়ে $@এবং $*, zshএবং bashএকই আচরণ করে, এবং আমি মনে করি ফলাফলের সব শাঁস মধ্যে বেশ মান হল:

 $ f () { for i in "$@"; do echo +"$i"+; done; }; f 'a a' 'b' ''
 +a a+
 +b+
 ++
 $ f () { for i in "$*"; do echo +"$i"+; done; }; f 'a a' 'b' ''
 +a a b +

উদ্ধৃতিবিহীন, ফলাফলগুলি এর জন্য $*এবং একই $@, তবে ভিতরে bashএবং ভিতরে পৃথক zsh। এই ক্ষেত্রে zshকিছু অদ্ভুত আচরণ দেখায়:

bash$ f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''
+a+
+a+
+b+
zsh% f () { for i in $*; do echo +"$i"+; done; }; f 'a a' 'b' ''  
+a a+
+b+

(Zsh সাধারণত আইএফএস ব্যবহার করে পাঠ্য ডেটা বিভক্ত করে না, স্পষ্টভাবে অনুরোধ না করা পর্যন্ত, তবে লক্ষ্য করুন যে এখানে খালি যুক্তি তালিকায় অপ্রত্যাশিতভাবে অনুপস্থিত রয়েছে।)


1
Zsh সালে $@এ ব্যাপারে বিশেষ নয়: $xবিস্তৃতি সবচেয়ে এক শব্দ, কিন্তু খালি ভেরিয়েবল কিছুই নেই (কোনো খালি শব্দ) এর প্রসারিত। খালি বা অপরিশোধিত print -l a $foo bদিয়ে চেষ্টা করুন foo
গিলস

0

উত্তরের একটি বলে $*(যা আমি "স্প্ল্যাট" হিসাবে মনে করি) খুব কমই কার্যকর useful

আমি সাথে গুগল অনুসন্ধান G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }

যেহেতু ইউআরএলগুলি প্রায়শই একটি দিয়ে বিভক্ত হয় +তবে আমার কীবোর্ডটি তার চেয়ে সহজেই পৌঁছনো সহজ করে তোলে   +, $*+ $IFSউপকারী মনে হয়।

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