বাশ: কোনও ফাংশনের আর্গুমেন্ট হিসাবে কমান্ডটি পাস করার পরে উদ্ধৃতিগুলি ছিনিয়ে নেওয়া হচ্ছে


8

আমি আমার স্ক্রিপ্টের জন্য একটি শুকনো রান ধরণের প্রক্রিয়াটি প্রয়োগ করার চেষ্টা করছি এবং যখন কোনও ক্রিয়াকলাপের পক্ষে একটি আর্গুমেন্ট হিসাবে কমান্ডটি পাস হয়ে যায় এবং ফলস্বরূপ অপ্রত্যাশিত আচরণের ফলে কোটগুলি ছিনিয়ে নেওয়া বন্ধ হয়ে যায়।

dry_run () {
    echo "$@"
    #printf '%q ' "$@"

    if [ "$DRY_RUN" ]; then
        return 0
    fi

    "$@"
}


email_admin() {
    echo " Emailing admin"
    dry_run su - $target_username  -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
    echo " Emailed"
    }

আউটপুট হল:

su - webuser1 -c cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com

প্রত্যাশিত:

su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"

প্রতিধ্বনির পরিবর্তে প্রিন্টফ সক্ষম হয়েছে:

su - webuser1 -c cd\ /home/webuser1/public_html\ \&\&\ git\ log\ -1\ -p\|mail\ -s\ \'Git\ deployment\ on\ webuser1\'\ user@domain.com

ফলাফল:

su: invalid option -- 1

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


উত্তর:


5

ন্যায়বিচারের \"পরিবর্তে ব্যবহার করার চেষ্টা করুন "


4

"$@"কাজ করা উচিত. আসলে এটি এই সাধারণ পরীক্ষার ক্ষেত্রে আমার জন্য কাজ করে:

dry_run()
{
    "$@"
}

email_admin()
{
    dry_run su - foo -c "cd /var/tmp && ls -1"
}

email_admin

আউটপুট:

./foo.sh 
a
b

যুক্ত করতে সম্পাদিত: আউটপুটটি echo $@সঠিক। "একটি মেটা-অক্ষর এবং প্যারামিটারের অংশ নয়। আপনি প্রমাণ করতে পারেন যে এটি সঠিকভাবে যোগ করে কাজ করছে echo $5থেকে dry_run()। এটি পরে সবকিছু আউটপুট হবে-c


4

এটি তুচ্ছ সমস্যা নয়। শেলটি ফাংশনটি কল করার আগে উদ্ধৃতি অপসারণ সম্পাদন করে, সুতরাং ফাংশনটি আপনি যেমন টাইপ করেছেন ঠিক তেমনভাবে পুনরায় তৈরি করার কোনও উপায় নেই।

তবে, আপনি যদি কমান্ডটি পুনরায় পাঠাতে কেবল অনুলিপি করতে এবং একটি কমানোর আটকানো স্ট্রিং মুদ্রণ করতে সক্ষম হতে চান তবে দুটি ভিন্ন পদ্ধতির আপনি নিতে পারেন:

  • মাধ্যমে চালিত হতে একটি কমান্ড স্ট্রিং তৈরি করুন evalএবং সেই স্ট্রিংটি পাস করুনdry_run
  • dry_runমুদ্রণের আগে কমান্ডের বিশেষ অক্ষরগুলি উদ্ধৃত করুন

ব্যবহার eval

আপনি evalকী চালাচ্ছেন তা মুদ্রণের জন্য আপনি কীভাবে এটি ব্যবহার করতে পারেন তা এখানে:

dry_run() {
    printf '%s\n' "$1"
    [ -z "${DRY_RUN}" ] || return 0
    eval "$1"
}

email_admin() {
    echo " Emailing admin"
    dry_run 'su - '"$target_username"'  -c "cd '"$GIT_WORK_TREE"' && git log -1 -p|mail -s '"'$mail_subject'"' '"$admin_email"'"'
    echo " Emailed"
}

আউটপুট:

su - webuser1  -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"

উদ্ধৃতি দেওয়ার পাগল পরিমাণটি নোট করুন - আপনি একটি কমান্ডের মধ্যে একটি কমান্ডের মধ্যে একটি কমান্ড পেয়েছেন, যা দ্রুত কুৎসিত হয়। সাবধান: উপরের কোডটিতে সমস্যা হবে যদি আপনার ভেরিয়েবলগুলিতে শ্বেত স্থান বা বিশেষ অক্ষর (কোটের মতো) থাকে।

বিশেষ অক্ষর উদ্ধৃতি

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

# This function prints each argument wrapped in single quotes
# (separated by spaces).  Any single quotes embedded in the
# arguments are escaped.
#
shell_quote() {
    # run in a subshell to protect the caller's environment
    (
        sep=''
        for arg in "$@"; do
            sqesc=$(printf '%s\n' "${arg}" | sed -e "s/'/'\\\\''/g")
            printf '%s' "${sep}'${sqesc}'"
            sep=' '
        done
    )
}

dry_run() {
    printf '%s\n' "$(shell_quote "$@")"
    [ -z "${DRY_RUN}" ] || return 0
    "$@"
}

email_admin() {
    echo " Emailing admin"
    dry_run su - "${target_username}"  -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
    echo " Emailed"
}

আউটপুট:

'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'

আপনি shell_quoteএকক উদ্ধৃতিতে সমস্ত কিছু মোড়কে না রেখে ব্যাকস্ল্যাশ-এস্কেপ বিশেষ চরিত্রে পরিবর্তন করে আউটপুটটির পঠনযোগ্যতা উন্নত করতে পারেন , তবে এটি সঠিকভাবে করা শক্ত।

আপনি যদি এই shell_quoteপদ্ধতিটি করেন, আপনি suনিরাপদ উপায়ে কমান্ডটি তৈরি করতে পারেন । নিম্নলিখিত কাজ এমনকি যদি হবে ${GIT_WORK_TREE}, ${mail_subject}অথবা ${admin_email}বিশেষ অক্ষর (একক উদ্ধৃতি, স্পেস, আস্টেরিক্স, সেমিকোলন, ইত্যাদি) অন্তর্ভুক্ত:

email_admin() {
    echo " Emailing admin"
    cmd=$(
        shell_quote cd "${GIT_WORK_TREE}"
        printf '%s' ' && git log -1 -p | '
        shell_quote mail -s "${mail_subject}" "${admin_email}"
    )
    dry_run su - "${target_username}"  -c "${cmd}"
    echo " Emailed"
}

আউটপুট:

'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''

2

এটি মুশকিল, আপনি দেখতে পারা এই অন্যান্য পদ্ধতির চেষ্টা করতে পারেন:

DRY_RUN=
#DRY_RUN=echo
....
email_admin() {
    echo " Emailing admin"
    $DRY_RUN su - $target_username  -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
    echo " Emailed"
    }

এইভাবে আপনি কেবল আপনার স্ক্রিপ্টের শীর্ষে ফাঁকা বা "প্রতিধ্বনি" তে DRY_RUN সেট করেছেন এবং এটি হয় বা কেবল এটি প্রতিধ্বনিত করে।


0

নিস চ্যালেঞ্জ :) এটা "সহজ" হওয়া উচিত যদি আপনি সমর্থন থেকে ব্যাশ সাম্প্রতিক যথেষ্ট আছে $LINENOএবং$BASH_SOURCE

এটি আপনার প্রয়োজন অনুসারে আশা করে আমার প্রথম প্রচেষ্টা:

#!/bin/bash
#adjust the previous line if needed: on prompt, do "type -all bash" to see where it is.    
#we check for the necessary ingredients:
[ "$BASH_SOURCE" = "" ] && { echo "you are running a too ancient bash, or not running bash at all. Can't go further" ; exit 1 ; }
[ "$LINENO" = "" ] && { echo "your bash doesn't support LINENO ..." ; exit 2 ; }
# we passed the tests. 
export _tab_="`printf '\011'`" #portable way to define it. It is used below to ensure we got the correct line, whatever separator (apart from a \CR) are between the arguments

function printandexec {
   [ "$FUNCNAME" = "" ] && { echo "your bash doesn't support FUNCNAME ..." ; exit 3 ; }
   #when we call this, we should do it like so :  printandexec $LINENO / complicated_cmd 'with some' 'complex arguments | and maybe quoted subshells'
   # so : $1 is the line in the $BASH_SOURCE that was calling this function
   #    : $2 is "/" , which we will use for easy cut
   #    : $3-... are the remaining arguments (up to next ; or && or || or | or #. However, we don't care, we use another mechanism...)
   export tmpfile="/tmp/printandexec.$$" #create a "unique" tmp file
   export original_line="$1"
   #1) display & save for execution:
   sed -e "${original_line}q;d" < ${BASH_SOURCE} | grep -- "${FUNCNAME}[ ${_tab_}]*\$LINENO" | cut -d/ -f2- | tee "${tmpfile}"
   #then execute it in the *current* shell so variables, etc are all set correctly:
   source ${tmpfile}
   rm -f "${tmpfile}"; #always have last command in a function finish by ";"

}

echo "we do stuff here:"
printandexec  $LINENO  / ls -al && echo "something else" #and you can even put commentaries!
#printandexec  $LINENO / su - $target_username  -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
#uncommented the previous on your machine once you're confident the script works
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.