কীভাবে কোনও সাবশেলে বাশ স্ক্রিপ্ট আর্গুমেন্টগুলি পাস করবেন


13

আমার কাছে একটি মোড়ক স্ক্রিপ্ট রয়েছে যা কিছু কাজ করে এবং তারপরে মূল প্যারামিটারগুলি অন্য সরঞ্জামে পাস করে:

#!/bin/bash
# ...
other_tool -a -b "$@"

"অন্য সরঞ্জাম" সাবসিলে চালিত না করা হলে এটি কাজ করে:

#!/bin/bash
# ...
bash -c "other_tool -a -b $@"

আমি যদি আমার মোড়ক স্ক্রিপ্টটিকে এভাবে কল করি:

wrapper.sh -x "blah blup"

তারপরে, কেবলমাত্র প্রথম অরগিনাল আর্গুমেন্ট (-x) "other_tool" - এর হাতে দেওয়া হয়। বাস্তবে, আমি একটি সাবশেল তৈরি করি না, তবে অ্যান্ড্রয়েড ফোনের শেলের কাছে মূল যুক্তিগুলি পাস করি, এতে কোনও পার্থক্য করা উচিত নয়:

#!/bin/bash
# ...
adb sh -c "other_tool -a -b $@"

উত্তর:


14

বাশের printfকমান্ডটিতে একটি বৈশিষ্ট্য রয়েছে যা উদ্ধৃতি / পলায়ন / যা কিছু স্ট্রিংই দেবে, যতক্ষণ না পিতা-মাতা এবং সাবশেল উভয়ই প্রকৃতপক্ষে বাশ, এটি কাজ করা উচিত:

[সম্পাদনা: সিয়েগি যেমন একটি মন্তব্যে উল্লেখ করেছেন, আপনি যদি কোন যুক্তি সরবরাহ না করা হয় তবে আপনি যদি স্পষ্টভাবে এটিরূপে সমস্যাটি করেন, যেখানে এটি বাস্তবে যেমন একটি একক খালি যুক্তি ছিল তেমন কাজ করে। আমি নীচে একটি কাজের জোড় যুক্ত করেছি, সাথে ফর্ম্যাট স্ট্রিং মোড়ানো ${1+}, যা প্রথম যুক্তি সংজ্ঞায়িত করা হয় তবে কেবলমাত্র বিন্যাসের স্ট্রিং অন্তর্ভুক্ত । এটি কিছুটা ক্লুজ, তবে এটি কাজ করে]]

#!/bin/bash

quoted_args="$(printf "${1+ %q}" "$@")" # Note: this will have a leading space before the first arg
# echo "Quoted args:$quoted_args" # Uncomment this to see what it's doing
bash -c "other_tool -a -b$quoted_args"

মনে রাখবেন যে আপনি এটি একক লাইনেও করতে পারেন: bash -c "other_tool -a -b$(printf "${1+ %q}" "$@")"


ধন্যবাদ! এটি আমার পক্ষে খুব ভাল কাজ করেছে।
DribblzAroundU82

এটি সঠিকভাবে কাজ করে না, যখন কোনও যুক্তি পাস করা হয় না (এটি কোনও আর্গুমেন্টের পরিবর্তে একটি ফাঁকা যুক্তি পাস করে)।
সিগি

1
@ সিগি ভাল ক্যাচ; আমি এটির জন্য একটি কর্মসূচী যুক্ত করেছি।
গর্ডন ডেভিসন

4

সমাধানগুলির কোনওটিই ভালভাবে কাজ করে না। মাত্র এক্স / \ Just \ "বি \" / আআআআ / \ 'এক্সএক্সএক্সএক্স \ ইয়াই \' / zz \ ​​"অফফ \" প্যারামিটার হিসাবে পাস করুন এবং সেগুলি ব্যর্থ হয়েছে।

এখানে একটি সহজ মোড়ক দেওয়া আছে যা প্রতিটি ক্ষেত্রে পরিচালনা করে। এটি প্রতিটি যুক্তিকে কীভাবে দুবার পালিয়ে যায় তা নোট করুন।

#!/usr/bin/env bash
declare -a ARGS
COUNT=$#
for ((INDEX=0; INDEX<COUNT; ++INDEX))
do
    ARG="$(printf "%q" "$1")"
    ARGS[INDEX]="$(printf "%q" "$ARG")"
    shift
done

ls -l ${ARGS[*]}

1
আপনি যদি '/ bin / foo' "$ @" "--opt" এর মতো একটি অবশেষে উদ্ধৃত স্ট্রিং আর্গুমেন্টের অংশ হিসাবে conc @ কে কনটেনেট করার চেষ্টা করছেন এবং এটি আবিষ্কার করছেন যে এটি আপনি প্রত্যাশা করছেন ঠিক তেমন বের হয় না ।
জুনিয়র

1
ওহ প্রভু ধন্যবাদ. এই সমস্যাটির সাথে লড়াই করে চলেছেন এবং দৃশ্যত কিছুই কার্যকর হয়নি। এটি এটি সমাধান। এই সমস্যাটিকে অনেক কিছু বিবেচনা করে বিবেচনা করে ডাবল পলায়নের জন্য অনুরোধ করা যদি কোনওভাবে অন্তর্নির্মিত বাশ হত তবে ভাল লাগবে।
MooGoo

2

পরিবর্তন $@করুন $*। আমি একটি ছোট স্থানীয় পরীক্ষা করেছি এবং এটি আমার ক্ষেত্রে কাজ করে।

#!/bin/sh
bash -c "echo $*"
bash -c "echo $@"

হিসাবে সংরক্ষণ করা test.shএবং এটি সম্পাদনযোগ্য দেয় making

$ ./test.sh foo bar
foo bar
foo

$*এবং $@আপনি যেমন দেখতে পাচ্ছেন তার মধ্যে একটি সূক্ষ্ম পার্থক্য রয়েছে । উদাহরণস্বরূপ দেখুন http://ss64.com/bash/syntax-paraters.html


মন্তব্যে ফলো-আপ প্রশ্নের জন্য: আপনাকে একটি পৃথক সংযুক্ত যুক্তি হিসাবে একটি স্ট্রিং পাস করতে উদাহরণস্বরূপ সাদা স্পেস "দু'বার" পালাতে হবে, যেমন test.shএকটি wcমোড়কে পরিবর্তিত :

#!/bin/sh
bash -c "wc $*"

এইটা কাজ করে:

$ touch test\ file
$ ./test.sh -l "test\ file"
0 test file

কিন্তু:

$ ./test.sh -l "test file"
wc: test: No such file or directory
wc: file: No such file or directory
0 total

দুর্ভাগ্যক্রমে, এটিও কাজ করে না। যদি আপনি wrapper.sh -x "blah blup"এইভাবে মোড়কে কল করেন: তবে সাবশেল টিউবিও (-x, "ব্লা ব্লুপ") এর পরিবর্তে তিনটি পরামিতি (-x, ব্লাহ, ব্লুপ) পায়
রাল্ফ হলি

আপনি যদি স্পেস বিভাজকটি সংরক্ষণ করতে চান, তবে আপনাকে যুক্তিটি "ডাবল-পলায়ন" করতে হবে "Blah\ blup"। এটি ব্যবহার করে দেখুন এবং এটি কাজ করে কিনা দেখুন।
ড্যানিয়েল অ্যান্ডারসন

2
দেখে মনে হচ্ছে এটি কাজ করে, তবে এটিকে পলাতক যুক্ত করার জন্য র্যাপার.শ এর কলার প্রয়োজন হবে এবং আমি একটি স্বচ্ছ সমাধানের সন্ধান করছি।
রাল্ফ হলি

2

এটি ব্যর্থ হচ্ছে কারণ আপনি একটি স্ট্রিতে একটি অ্যারে (অবস্থানগত পরামিতি) চাপছেন। "$@"magন্দ্রজালিক কারণ এটি আপনাকে যথাযথভাবে উদ্ধৃত স্ট্রিং হিসাবে প্রতিটি পৃথক পরামিতি দেয়। অতিরিক্ত পাঠ্য যুক্ত করা যাদুটিকে ভেঙে দেয়: "blah $@"এটি কেবল একটি স্ট্রিং।

এটি আপনাকে আরও কাছে পেতে পারে:

cmd="other_tool -a -b"
for parm in "$@"; do cmd+=" '$parm'"; done
adb sh -c "$cmd"

অবশ্যই, যে কোনও প্যারামিটারে একটি একক উদ্ধৃতি ঝামেলা সৃষ্টি করবে।


2

ঠিক আছে, আরও ব্যাখ্যা:

$ cat /tmp/test.sh
#! /bin/bash

echo '$@='"$@"

set -v # "debug"

sh -c 'echo $@' "$@" # gremlins steal the first option

sh -c 'echo $@' -- "$@" # We defend the option with two knifes

$ bash -e /tmp/test.sh first second third
$@=first second third

sh -c 'echo $@' "$@" # gremlins steal the first option
second third

sh -c 'echo $@' -- "$@" # We defend the option with two knifes
first second third

1

আমি অনেকগুলি বিভিন্ন সমাধান চেষ্টা করেছি, পটভূমির তথ্য এবং বিকল্প সহ একটি ভাল সংস্থান উদাহরণস্বরূপ গ্রেগের (ওরফে। গ্রেগ্যাটিক্স) উইকিতে বাশফ্যাউ / ০৯6 । একসাথে আমি নিম্নলিখিত দুটি সর্বাধিক পঠনযোগ্য (শ্রমজীবী ​​থেকে) পেয়েছি:


4.4 বাশ ( যেহেতু আমি NEWS থেকে বলতে পারি ) প্যারামিটার সম্প্রসারণটি @Q এভাবে ব্যবহার করা সম্ভব :

adb sh -c "other_tool -a -b ${*@Q}"

নোট করুন যে আমি $*এখানে পরিবর্তে ব্যবহার করেছি $@কারণ আপনি "other_tool -a -b ${*@Q}"যুক্তি অনুসারে এক স্ট্রিংয়ের পরিবর্তে একটি একক স্ট্রিং হতে চান ।

আপনি যদি ব্যাশ অ্যারে ভেরিয়েবলের সাথে একই কাজ করতে চান তবে আপনার সিনট্যাক্সটি ${ARRAY[*]@Q}(উদ্ধৃতিগুলির মধ্যে) প্রয়োজন হবে।


আপনার কাছে যদি 4.4 বাশ বা তার পরে পাওয়া না যায় বা নিশ্চিত না হন তবে এটি আমার পছন্দসই সমাধান:

function escapeBashArgs() {
    local arg separator=""
    for arg
    do
        printf "%s%q" "$separator" "$arg"
        separator=" "
    done
}

adb sh -c "other_tool -a -b $(escapeBashArgs "$@")"

নোট করুন যে এখানে বা "$@"পরিবর্তে আপনার বা যুক্তিগুলির মধ্যে শব্দ বিভাজন চান না, সুতরাং উদ্ধৃতি ব্যতীত রূপগুলি ব্যবহার করা যাবে না, এবং আপনি চান যে যুক্তির সংখ্যা সংরক্ষণ করা উচিত, সুতরাং এটি যুক্ত হওয়ার সাথে ব্যবহার করা যাবে না একটি একক স্ট্রিং সমস্ত আর্গুমেন্ট। ফাংশন তারপরে সমস্ত আর্গুমেন্টকে একটি স্ট্রিংয়ে ফিরিয়ে দেয়।$@"$*"$*"$*"

আপনি যদি প্রথম তর্কটির সামনে অতিরিক্ত স্থান সম্পর্কে চিন্তা না করেন তবে আপনি printfবিন্যাসের স্ট্রিংটি পরিবর্তন করতে " %q"এবং separatorপরিবর্তনশীলটি সরাতে পারেন । অথবা আপনি গর্ডন ডেভিসন উত্তর থেকে ওয়ান-লাইনার ব্যবহার করতে পারেন ।


এই সমাধানগুলি সমস্ত ক্ষেত্রেই কাজ করে যা আমি নিয়ে আসতে পারি, বিশেষত:

  • কোন যুক্তি: escapeBashArgsকিছুই
  • খালি যুক্তি: escapeBashArgs "" ""'' ''
  • কেবল ফাঁকা জায়গার সাথে যুক্তিগুলি: escapeBashArgs " " " "' ' ' 'বা \ \ \ \ \( শেষ স্থানটি এই সাইটগুলি রেন্ডারার খেয়েছে )
  • বিশেষ ব্যবধান এবং নিউলাইনগুলির সাথে যুক্তি: escapeBashArgs "a b" c\ d "arg with newline"'a b' 'c d' $'arg with\nnewline'বা a\ \ \ \ \ \ b c\ d $'arg with\nnewline'( নতুন লাইনের মধ্যে রয়েছে withএবং newlineঅন্যান্য অবস্থানে এটি এই সাইটে লাইন মোড়ানোর কারণে )
  • বিশেষ অক্ষরের সাথে যুক্তি: escapeBashArgs '$"'\''({:})''$"'\''({:})'বা\$\"\'\(\{:\}\)
  • জ্যাকায়াজাকের উত্তর থেকে উদাহরণ : escapeBashArgs x/\ \ \"b\"/aaaaa/\'xxx\ yyyy\'/zz\"offf\"'x/ "b"/aaaaa/'\''xxx yyyy'\''/zz"offf"'বাx/\ \ \"b\"/aaaaa/\'xxx\ yyyy\'/zz\"offf\"

(জিএনইউ বাশ 5.0.3 (1) -রিলিজ দিয়ে পরীক্ষিত


-2
#! /bin/bash
sh -c 'other_tool -a -b "$@"' -- "$@"

3
সুপার ব্যবহারকারীকে স্বাগতম! আমরা দীর্ঘ উত্তর খুঁজছি যা কিছু ব্যাখ্যা এবং প্রসঙ্গ সরবরাহ করে। শুধু একটি লাইনের উত্তর দেবেন না; আপনার উত্তর কেন সঠিক তা ব্যাখ্যা করুন, আদর্শভাবে উদ্ধৃতি দিয়ে। ব্যাখ্যাগুলি অন্তর্ভুক্ত না করে এমন উত্তরগুলি সরানো হতে পারে।
জি-ম্যান বলছেন 'মনিকাকে পুনরায় ইনস্টল করুন'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.