Ssh $ হোস্ট $ এফইউও এবং এসএসএইচ-হোস্টে উদ্ধৃতি দেওয়া হচ্ছে "সুডো সু ইউজার-সি” এফও "টাইপ কনস্ট্রাক্টস


30

আমি প্রায়শই ssh এর উপর জটিল কমান্ড জারি করি; এই কমান্ডগুলির মধ্যে এক-লাইনগুলিকে বিশ্রী বা পার্ল করার জন্য পাইপিং জড়িত রয়েছে এবং ফলস্বরূপ একক উদ্ধৃতি এবং। 'গুলি থাকে। উদ্ধৃতিটি সঠিকভাবে করার জন্য আমি কোনও কঠোর এবং দ্রুত নিয়ম বের করতে সক্ষম হয়েছি বা এর পক্ষে ভাল কোনও রেফারেন্স পাইনি। উদাহরণস্বরূপ, নিম্নলিখিত বিবেচনা করুন:

# what I'd run locally:
CMD='pgrep -fl java | grep -i datanode | awk '{print $1}'
# this works with ssh $host "$CMD":
CMD='pgrep -fl java | grep -i datanode | awk '"'"'{print $1}'"'"

(অ্যাডব্লিক স্টেটমেন্টে অতিরিক্ত উদ্ধৃতিগুলি নোট করুন))

তবে আমি কীভাবে এটি দিয়ে কাজ করতে পারি ssh $host "sudo su user -c '$CMD'"? এই জাতীয় দৃশ্যে কোট পরিচালনা করার জন্য কি কোনও সাধারণ রেসিপি আছে? ..

উত্তর:


35

একাধিক স্তরের উদ্ধৃতি (প্রকৃতপক্ষে, বিশ্লেষণ / ব্যাখ্যার একাধিক স্তর) নিয়ে কাজ করা জটিল হতে পারে। এটি কয়েকটি বিষয় মাথায় রাখতে সহায়তা করে:

  • প্রতিটি "উদ্ধৃতি স্তর" সম্ভাব্যভাবে একটি আলাদা ভাষা জড়িত করতে পারে।
  • উদ্ধৃতি বিধিগুলি ভাষা অনুসারে পৃথক হয়।
  • এক বা দু'টির বেশি নেস্টেড স্তরের সাথে কাজ করার সময়, "নীচ থেকে উপরে" (অর্থাত্ অভ্যন্তরীণ থেকে বহির্মুখী) কাজ করা সহজ is

উদ্ধৃতি স্তর

আসুন আপনার উদাহরণ কমান্ড দেখুন।

pgrep -fl java | grep -i datanode | awk '{print $1}'

আপনার শেল, ইন Regex: (উপরে) আপনার প্রথম উদাহরণ কমান্ড চার ভাষায় ব্যবহার pgrep মধ্যে Regex , grep (যেখানে Regex ভাষা থেকে আলাদা হতে পারে pgrep ), এবং awk । এর সাথে ব্যাখ্যার দুটি স্তর রয়েছে: শেল এবং জড়িত প্রতিটি আদেশের শেলের পরে একটি স্তর। উদ্ধৃতি দেওয়ার জন্য কেবলমাত্র একটি স্পষ্ট স্তর রয়েছে ( শাঁসকে কোষে উদ্ধৃত করা )।

ssh host 

এরপরে আপনি শীর্ষে ssh এর একটি স্তর যুক্ত করেছেন । এটি কার্যকরভাবে অন্য শেল স্তর: ssh কমান্ডটি নিজেই ব্যাখ্যা করে না, এটি এটিকে দূরবর্তী প্রান্তের (যেমন (যেমন) sh -c …) একটি শেলের হাতে দেয় এবং সেই শেলটি স্ট্রিংটিকে ব্যাখ্যা করে।

ssh host "sudo su user -c …"

তারপরে আপনি su ব্যবহার করে মাঝখানে আরও একটি শেল স্তর যুক্ত করার বিষয়ে জিজ্ঞাসা করেছিলেন ( sudo এর মাধ্যমে , যা এর কমান্ড আর্গুমেন্টকে ব্যাখ্যা করে না, তাই আমরা এটিকে উপেক্ষা করতে পারি)। এই মুহুর্তে, আপনার কাছে নেস্টিংয়ের তিনটি স্তর চলছে ( অ্যাডব্লক- শেল, শেল-শেল ( এসএসএস ), শেল-শেল ( সু ইউজার-সি ), তাই আমি "নীচে, আপ" পদ্ধতির ব্যবহারের পরামর্শ দিচ্ছি I আমি ধরে নেব আপনার শেলগুলি বোর্ন সামঞ্জস্যপূর্ণ (যেমন , ছাই , ড্যাশ , কেএস , বাশ , জেডএস , ইত্যাদি) Some অন্য কিছু ধরণের শেল ( ফিশ , আরসি), ইত্যাদি) বিভিন্ন সিনট্যাক্সের প্রয়োজন হতে পারে তবে পদ্ধতিটি এখনও প্রয়োগ হয়।

নীচে, উপরে

  1. অন্তর্নিহিত স্তরে আপনি যে স্ট্রিংটি উপস্থাপন করতে চান তা তৈরি করুন।
  2. পরবর্তী সর্বোচ্চ ভাষার ভাষার উদ্ধৃতি তালিকা থেকে একটি উদ্ধৃতি ব্যবস্থা নির্বাচন করুন।
  3. আপনার নির্বাচিত উদ্ধৃতি পদ্ধতি অনুসারে কাঙ্ক্ষিত স্ট্রিংটি উদ্ধৃত করুন।
    • কোন কোটিং মেকানিজম প্রয়োগ করতে হয় তা প্রায়শই বিভিন্ন রকম হয়। এটি হাতে হাতে করা সাধারণত অনুশীলন এবং অভিজ্ঞতার বিষয়। এটি অগ্রগতি সম্পন্ন করার সময়, ডান দিক থেকে পাওয়া সবচেয়ে সহজ চয়ন করা সাধারণত ভাল (সাধারণত "সবচেয়ে আক্ষরিক" (খুব কম সংখ্যক পালিয়ে যাওয়া)) বেছে নেওয়া ভাল।
  4. Allyচ্ছিকভাবে, অতিরিক্ত কোড সহ ফলাফলের উদ্ধৃত স্ট্রিংটি ব্যবহার করুন।
  5. যদি আপনি এখনও আপনার উদ্ধৃতি / ব্যাখ্যার কাঙ্ক্ষিত স্তরে পৌঁছায় না, তবে ফলাফলের উদ্ধৃত স্ট্রিংটি (কোনও সংযুক্ত কোড যুক্ত করুন) নিন এবং পদক্ষেপ 2-এ এটি সূচনা স্ট্রিং হিসাবে ব্যবহার করুন।

শব্দার্থবিজ্ঞানের বিভিন্ন উদ্ধৃতি

এখানে মনে রাখা জিনিসটি হ'ল প্রতিটি ভাষা (উদ্ধৃতি স্তর) একই উদ্ধৃতি চরিত্রটিকে কিছুটা আলাদা শব্দার্থবিজ্ঞান (বা এমনকি মারাত্মকভাবে পৃথক পৃথক শব্দার্থক) দিতে পারে।

বেশিরভাগ ভাষায় একটি "আক্ষরিক" উদ্ধৃতকরণ প্রক্রিয়া থাকে তবে সেগুলি কতটা আক্ষরিক সেগুলির পরিবর্তিত হয়। বোর্নের মতো শেলগুলির একক উদ্ধৃতিটি আসলে আক্ষরিক (যার অর্থ আপনি এটি কোনও একক উদ্ধৃতি চরিত্রের উদ্ধৃতিতে ব্যবহার করতে পারবেন না)। অন্যান্য ভাষাগুলি (পার্ল, রুবি) কম আক্ষরিক, কারণ তারা একক উদ্ধৃত অঞ্চলে কিছু ব্যাকস্ল্যাশ অনুক্রমের ব্যাখ্যা অক্ষরহীন (বিশেষত, \\এবং \'ফলাফল এবং \এবং ', কিন্তু অন্যান্য ব্যাকস্ল্যাশ ক্রমগুলি আসলে আক্ষরিক)।

আপনার প্রতিটি ভাষার এর উদ্ধৃতি বিধি এবং সামগ্রিক বাক্য গঠন বোঝার জন্য আপনাকে ডকুমেন্টেশন পড়তে হবে।

আপনার উদাহরণ

আপনার উদাহরণের অন্তর্নিহিত স্তরটি হ'ল একটি অ্যাডক প্রোগ্রাম।

{print $1}

আপনি এটি শেল কমান্ড লাইনে এম্বেড করতে চলেছেন:

pgrep -fl java | grep -i datanode | awk 

আমরা (ক অন্তত) রক্ষা করার জন্য স্থান এবং প্রয়োজন $মধ্যে awk প্রোগ্রাম। স্পষ্ট পছন্দটি হ'ল পুরো প্রোগ্রামটির চারপাশে শেলের মধ্যে একক উদ্ধৃতি ব্যবহার করা।

  • '{print $1}'

যদিও অন্যান্য পছন্দ আছে:

  • {print\ \$1} সরাসরি স্থান এবং অবকাশ $
  • {print' $'1} একক উদ্ধৃতি শুধুমাত্র স্থান এবং $
  • "{print \$1}" পুরো ডাবল উদ্ধৃতি এবং পালাতে $
  • {print" $"1}ডাবল উদ্ধৃতি কেবল স্থান এবং $
    এটি নিয়মগুলি কিছুটা বাঁকানো হতে পারে ( $একটি দ্বিগুণ উদ্ধৃত স্ট্রিংয়ের শেষে অবরুদ্ধ আক্ষরিক), তবে এটি বেশিরভাগ শেলগুলিতে কাজ করে বলে মনে হচ্ছে।

যদি প্রোগ্রামটি খোলা এবং ঘনিষ্ঠ কোঁকড়ানো ধনুর্বন্ধনীগুলির মধ্যে একটি কমা ব্যবহার করে তবে আমাদের কিছু শাঁকের "ব্রেস সম্প্রসারণ" এড়াতে কমা বা কোঁকড়া ধনুর্বন্ধনীগুলির উদ্ধৃতি বা পালাতে হবে।

আমরা '{print $1}'এটিকে বাকি শেল "কোড" এ বাছাই করে এম্বেড করি:

pgrep -fl java | grep -i datanode | awk '{print $1}'

এর পরে, আপনি এটি su এবং sudo এর মাধ্যমে চালাতে চেয়েছিলেন ।

sudo su user -c 

su user -c …ঠিক যেমন some-shell -c …(কিছু অন্যান্য ইউআইডি এর অধীনে চলমান ব্যতীত), তাই সু আরও একটি শেল স্তর যুক্ত করে। sudo এর যুক্তিগুলি ব্যাখ্যা করে না, সুতরাং এটি কোনও উদ্ধৃতি স্তর যুক্ত করে না।

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

'pgrep -fl java | grep -i datanode | awk '\''{print $1}'\'

এখানে চারটি স্ট্রিং রয়েছে যা শেলটি ব্যাখ্যা করবে এবং সংশ্লেষ করবে: প্রথম একক উদ্ধৃত স্ট্রিং ( pgrep … awk), একটি পালানো একক উদ্ধৃতি, একক উদ্ধৃত অ্যাজ প্রোগ্রাম, অন্যটি একক উদ্ধৃতি থেকে রক্ষা পেয়েছে

অবশ্যই অনেকগুলি বিকল্প রয়েছে:

  • pgrep\ -fl\ java\ \|\ grep\ -i\ datanode\ \|\ awk\ \'{print\ \$1} গুরুত্বপূর্ণ সবকিছু এড়ান
  • pgrep\ -fl\ java\|grep\ -i\ datanode\|awk\ \'{print\$1}একই, তবে অতিরিক্ত অতিরিক্ত সাদা স্থান ছাড়াই (এমনকি অ্যাজক প্রোগ্রামেও!)
  • "pgrep -fl java | grep -i datanode | awk '{print \$1}'" ডাবল উদ্ধৃতি পুরো জিনিস, পালাতে $
  • 'pgrep -fl java | grep -i datanode | awk '"'"'{print \$1}'"'"আপনার প্রকরণ; ডাবল উদ্ধৃতি (দুটি অক্ষর) পলায়নের পরিবর্তে (একটি অক্ষর) ব্যবহারের কারণে স্বাভাবিক উপায়ে কিছুটা দীর্ঘ

প্রথম স্তরে বিভিন্ন উদ্ধৃতি ব্যবহার করা এই স্তরে অন্যান্য ভিন্নতার জন্য অনুমতি দেয়:

  • 'pgrep -fl java | grep -i datanode | awk "{print \$1}"'
  • 'pgrep -fl java | grep -i datanode | awk {print\ \$1}'

Sudo / * su * কমান্ড লাইনে প্রথম প্রকারের এম্বেড করা এটি দিন :

sudo su user -c 'pgrep -fl java | grep -i datanode | awk '\''{print $1}'\'

আপনি অন্য কোনও একক শেল স্তরের প্রসঙ্গে (যেমন ssh host …) একই স্ট্রিংটি ব্যবহার করতে পারেন ।

এরপরে, আপনি শীর্ষে ssh এর একটি স্তর যুক্ত করেছেন । এটি কার্যকরভাবে অন্য শেল স্তর: ssh কমান্ডটি নিজেই ব্যাখ্যা করে না, তবে এটি এটিকে দূরবর্তী প্রান্তের (যেমন (যেমন) sh -c …) একটি শেলের হাতে দেয় এবং সেই শেলটি স্ট্রিংটিকে ব্যাখ্যা করে।

ssh host 

প্রক্রিয়াটি একই: স্ট্রিং নিন, একটি উদ্ধৃতি পদ্ধতি চয়ন করুন, এটি ব্যবহার করুন, এম্বেড করুন।

আবার একক উদ্ধৃতি ব্যবহার:

'sudo su user -c '\''pgrep -fl java | grep -i datanode | awk '\'\\\'\''{print $1}'\'\\\'

এখন সেখানে এগারো স্ট্রিং যে ব্যাখ্যা এবং ঘনিভূত হয়: 'sudo su user -c ',, একক উদ্ধৃতি পলান 'pgrep … awk ', একক কোট, পলান ব্যাকস্ল্যাশ, দুই একক উদ্ধৃতি পলান, একক উদ্ধৃত পলান awk প্রোগ্রাম, একটি একক উদ্ধৃতি, একটি পলান ব্যাকস্ল্যাশ পলান, এবং একটি চূড়ান্ত একক উদ্ধৃতি পলান ।

চূড়ান্ত ফর্মটি দেখে মনে হচ্ছে:

ssh host 'sudo su user -c '\''pgrep -fl java | grep -i datanode | awk '\'\\\'\''{print $1}'\'\\\'

হাত দ্বারা টাইপ করা এটি কিছুটা অযৌক্তিক, তবে শেলের একক উদ্ধৃতিতে আক্ষরিক প্রকৃতি এটিকে কিছুটা প্রকারের স্বয়ংক্রিয়করণ সহজ করে তোলে:

#!/bin/sh

sq() { # single quote for Bourne shell evaluation
    # Change ' to '\'' and wrap in single quotes.
    # If original starts/ends with a single quote, creates useless
    # (but harmless) '' at beginning/end of result.
    printf '%s\n' "$*" | sed -e "s/'/'\\\\''/g" -e 1s/^/\'/ -e \$s/\$/\'/
}

# Some shells (ksh, bash, zsh) can do something similar with %q, but
# the result may not be compatible with other shells (ksh uses $'...',
# but dash does not recognize it).
#
# sq() { printf %q "$*"; }

ap='{print $1}'
s1="pgrep -fl java | grep -i datanode | awk $(sq "$ap")"
s2="sudo su user -c $(sq "$s1")"

ssh host "$(sq "$s2")"

5
দুর্দান্ত ব্যাখ্যা!
গিলস

7

একটি সাধারণ সমাধান সহ সুস্পষ্ট, গভীর-গভীরতার জন্য ক্রিস জনসনের উত্তর দেখুন । আমি কয়েকটি অতিরিক্ত টিপস দিচ্ছি যা কিছু সাধারণ পরিস্থিতিতে সহায়তা করে।

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

su -c "grep '$pattern' /root/file"  # assuming there is no ' in $pattern

যদি আপনার স্থানীয় শেলটি ksh93 বা zsh হয় তবে আপনি ভেরিয়েবলটিতে পুনরায় লিখে একক উদ্ধৃতি দিয়ে মোকাবেলা করতে পারেন '\''। (যদিও বাশেরও ${foo//pattern/replacement}নির্মাণ রয়েছে, এটির একক উদ্ধৃতিগুলি পরিচালনা করা আমার কোনও অর্থবোধ করে না))

su -c "grep '${pattern//'/'\''}' /root/file"  # if the outer shell is zsh
su -c "grep '${pattern//\'/\'\\\'\'}' /root/file"  # if the outer shell is ksh93

নেস্টেড কোটিংয়ের সাথে মোকাবেলা না করার আরেকটি পরামর্শ হ'ল পরিবেশের ভেরিয়েবলের মাধ্যমে যতটা সম্ভব স্ট্রিংগুলি পাস করা। এসএসএস এবং সুডো বেশিরভাগ পরিবেশের ভেরিয়েবলগুলি ফেলে রাখার প্রবণতা রাখে তবে এগুলি প্রায়শই ব্যবহারের জন্য কনফিগার করা LC_*হয় কারণ এগুলি সাধারণত ব্যবহারের জন্য খুব গুরুত্বপূর্ণ (এগুলিতে স্থানীয় তথ্য রয়েছে) এবং এটি খুব কমই সুরক্ষা সংবেদনশীল হিসাবে বিবেচিত হয়।

LC_CMD='what you would use locally' ssh $host 'sudo su user -c "$LC_CMD"'

এখানে, যেহেতু LC_CMDএকটি শেল স্নিপেট রয়েছে তাই এটি অবশ্যই অভ্যন্তরীণতম শেলকে আক্ষরিকভাবে সরবরাহ করতে হবে। অতএব তাত্ক্ষণিকভাবে শেল দ্বারা তাত্ক্ষণিকভাবে প্রসারিত হয়। অন্তঃস্থ-তবে-একটি শেলটি দেখায় "$LC_CMD"এবং অন্তঃস্থ শেলটি কমান্ডগুলি দেখে।

একটি পাঠ্য প্রক্রিয়াজাতকরণ ইউটিলিটিতে ডেটা পাস করতে অনুরূপ পদ্ধতিটি কার্যকর। যদি আপনি শেল ইন্টারপোলেশন ব্যবহার করেন তবে ইউটিলিটি ভেরিয়েবলের মান একটি কমান্ড হিসাবে বিবেচনা করবে, যেমন sed "s/$pattern/$replacement/"ভেরিয়েবলগুলি অন্তর্ভুক্ত থাকলে কাজ করবে না /। সুতরাং উইন্ড (সিড নয়) এবং শেল থেকে ডেটা পাস করার জন্য এর -vবিকল্প বা ENVIRONঅ্যারের ব্যবহার করুন (যদি আপনি যান ENVIRONতবে ভেরিয়েবলগুলি রফতানি করার বিষয়টি মনে রাখবেন)।

awk -vpattern="$pattern" replacement="$replacement" '{gsub(pattern,replacement); print}'

2

ক্রিস জনসন যেহেতু খুব ভাল বর্ণনা করেছেন , আপনার এখানে উদ্ধৃত ইন্ডায়ারেশনের কয়েকটি স্তর রয়েছে; আপনার স্থানীয় নির্দেশ shellদূরবর্তী নির্দেশ shellমাধ্যমে sshএটি নির্দেশ দিতে sudoনির্দেশ suদূরবর্তী নির্দেশ shellআপনার পাইপলাইন চালানোর জন্য pgrep -fl java | grep -i datanode | awk '{print $1}'যেমন user। এই জাতীয় কমান্ড অনেক ক্লান্তিকর প্রয়োজন \'"quote quoting"\'

আপনি যদি আমার পরামর্শ গ্রহণ করেন, আপনি সমস্ত বাজে কথা পূর্বেই রেখে দিন এবং করবেন:

% ssh $host <<REM=LOC_EXPANSION <<'REMOTE_CMD' |
> localhost_data='$(commands run on localhost at runtime)' #quotes don't affect expansion
> more_localhost_data="$(values set at heredoc expansion)" #remote shell will receive m_h_d="result"
> REM=LOC_EXPANSION
> commands typed exactly as if located at 
> the remote terminal including variable 
> "${{more_,}localhost_data}" operations
> 'quotes and' \all possibly even 
> a\wk <<'REMOTELY_INVOKED_HEREDOC' |
> {as is often useful with $awk
> so long as the terminator for}
> REMOTELY_INVOKED_HEREDOC
> differs from that of REM=LOC_EXPANSION and
> REMOTE_CMD
> and here you can | pipeline operate on |\
> any output | received from | ssh as |\
> run above | in your local | terminal |\
> however | tee > ./you_wish.result
<desired output>

আরো বেশী:

স্ল্যাশ প্রতিস্থাপনের জন্য বিভিন্ন ধরণের উদ্ধৃতি সহ পাইপিংয়ের পাথগুলিতে আমার (সম্ভবত খুব দীর্ঘ-বায়ুযুক্ত) উত্তরটি যাচাই করুন যাতে আমি কেন এটি কাজ করে তার পিছনে কিছু তত্ত্ব আলোচনা করি।

-Mike


এটি আকর্ষণীয় দেখায় তবে আমি এটি কাজ করতে পারি না। আপনি কি ন্যূনতম কাজের উদাহরণ পোস্ট করতে পারেন?
জন লরেন্স অ্যাসপডেন

আমি বিশ্বাস করি যে এই উদাহরণটির জন্য zsh প্রয়োজন কারণ এটি স্টিডিনে একাধিক পুনঃনির্দেশগুলি ব্যবহার করে। অন্য বোর্নের মতো শেলগুলিতে, দ্বিতীয়টি <<প্রথমটি প্রথমটি প্রতিস্থাপন করে। এটি কোথাও "zsh" বলতে হবে, বা আমি কিছু মিস করেছি? (যদিও চতুর কৌশল, আংশিকভাবে স্থানীয় বিস্তারের সাপেক্ষে এমন একটি

এখানে একটি বাশ সামঞ্জস্যপূর্ণ সংস্করণটি রয়েছে: unix.stackexchange.com/questions/422489/…
dabest1

0

আরও ডাবল উদ্ধৃতি ব্যবহার সম্পর্কে কীভাবে?

তাহলে আপনার ssh $host $CMDএটির সাথে ঠিক কাজ করা উচিত:

CMD="pgrep -fl java | grep -i datanode | awk '{print $1}'"

এখন আরও জটিল এক ssh $host "sudo su user -c \"$CMD\""। আমি তোমাদের সংবেদনশীল অক্ষর অব্যাহতি যা করতে হবে অনুমান CMD: $, \এবং "। তাই আমি চেষ্টা করুন এবং যদি এই কাজ দেখতে না: echo $CMD | sed -e 's/[$\\"]/\\\1/g'

যদি এটি ঠিক দেখা যায়, তবে শেল ফাংশনটিতে প্রতিধ্বনি + এসডে আবদ্ধ করুন এবং আপনি যাবেন ভাল ssh $host "sudo su user -c \"$(escape_my_var $CMD)\""

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