ফাঁদ, ERR, এবং ত্রুটি লাইন প্রতিধ্বনি


30

আমি সমস্ত ত্রুটিতে ফাংশন কল করতে ট্র্যাপ ব্যবহার করে কিছু ত্রুটি প্রতিবেদন তৈরি করার চেষ্টা করছি:

Trap "_func" ERR

ইআরআর সিগন্যালটি কোন রেখা থেকে পাঠানো হয়েছিল তা পাওয়া সম্ভব? শেল বাশ।

যদি আমি এটি করি তবে আমি পড়তে এবং কী আদেশটি ব্যবহৃত হয়েছিল তা প্রতিবেদন করতে এবং কিছু ক্রিয়া লগ / সম্পাদন করতে পারি।

বা সম্ভবত আমি এই সব ভুল করছি?

আমি নিম্নলিখিতটি দিয়ে পরীক্ষা করেছি:

#!/bin/bash
trap "ECHO $LINENO" ERR

echo hello | grep "asdf"

এবং $LINENOফিরে আসছে 2. কাজ করছে না।


আপনি ব্যাশ ডিবাগার স্ক্রিপ্টটি দেখতে পারেন bashdb। দেখে মনে হচ্ছে যে প্রথম যুক্তিতে trapভেরিয়েবল থাকতে পারে যা পছন্দসই প্রসঙ্গে মূল্যায়ন করা হয়। তাই trap 'echo $LINENO' ERR'কাজ করা উচিত।
donothingsuccessfully

হুম ঠিক একটি খারাপ প্রতিধ্বনি দিয়ে এটি চেষ্টা করে | গ্রেপ কমান্ড এবং এটি ট্র্যাপ স্টেটমেন্টের লাইনটি প্রদান করে। তবে আমি বাশদ্বির দিকে একবার নজর দেব
মেছাফ্ল্যাশ

আমি খুব দুঃখিত ... আমি আমার মূল প্রশ্নে সুনির্দিষ্টভাবে উল্লেখ করতে পারি নি যে আমার একটি স্থানীয় সমাধান প্রয়োজন। আমি প্রশ্নটি সম্পাদনা করেছি।
মেছাফ্ল্যাশ

দুঃখিত, আমি উদাহরণস্বরূপ লাইন borked: trap 'echo $LINENO' ERR। প্রথম যুক্তিটি trapসম্পূর্ণ echo $LINENOহার্ডকোয়েটেড। এই বাশ আছে।
donothingsuccessfully

5
@ মেছাফ্ল্যাশ এটি trap 'echo $LINENO' ERRএকক উদ্ধৃতি সহ ডাবল কোট নয়, থাকতে হবে । আপনি যে কমান্ডটি লিখেছিলেন $LINENOতা দিয়ে প্রসারিত হয় যখন লাইন 2 পার্স করা হয়, সুতরাং ফাঁদটি হয় echo 2(বা বরং ECHO 2, যা আউটপুট হবে bash: ECHO: command not found)।
গিলস 'খারাপ হয়ে যাওয়া বন্ধ করুন'

উত্তর:


61

মন্তব্যে নির্দেশিত হিসাবে, আপনার উদ্ধৃতিটি ভুল। $LINENOযখন ট্র্যাপ লাইনটি প্রথম পার্স করা হয় তখন আপনাকে প্রসারিত হওয়া থেকে বিরত রাখতে আপনার একক উদ্ধৃতি দরকার ।

এইটা কাজ করে:

#! /bin/bash

err_report() {
    echo "Error on line $1"
}

trap 'err_report $LINENO' ERR

echo hello | grep foo  # This is line number 9

এটি চালানো:

 $ ./test.sh
 Error on line 9

একটি ফাংশন কল দিয়ে উদাহরণের জন্য ধন্যবাদ। আমি জানতাম না যে ডাবল উক্তিগুলি এই ক্ষেত্রে ভেরিয়েবলটি প্রসারিত করেছিল।
মেছাফ্ল্যাশ

echo hello | grep fooআমার জন্য ত্রুটি ছুঁড়েছে বলে মনে হচ্ছে না। আমি কি কিছু ভুল বুঝছি?
ভূগোলিক

@ জিওথোরি আমার সিস্টেমে grepএকটি ম্যাচ থাকলে 0 এর প্রস্থান স্থিতি রয়েছে, কোনও মিল নেই যদি 1 এবং ত্রুটির জন্য> 1। আপনি আপনার সিস্টেমে আচরণটি পরীক্ষা করতে পারেনecho hello | grep foo; echo $?
প্যাট্রিক

না আপনি ঠিক বলেছেন এটি একটি ত্রুটি :)
ভূতত্ত্ব

কমান্ড ব্যর্থতায় ত্রুটি সৃষ্টি করার জন্য, আপনাকে অনুরোধ লাইনে -e ব্যবহার করার দরকার নেই? তা হ'ল: #! / বিন / বাশ -e?
টিম বার্ড

14

আপনি ব্যাশ বিল্টিন 'কলার' ব্যবহার করতে পারেন:

#!/bin/bash

err_report() {
  echo "errexit on line $(caller)" >&2
}

trap err_report ERR

echo hello | grep foo

এটি ফাইলের নামও প্রিন্ট করে:

$ ./test.sh
errexit on line 9 ./test.sh

6

আমি উপরের @ ম্যাট দ্বারা প্রদত্ত উত্তরটি সত্যিই পছন্দ করি। এটির ভিত্তিতে আমি একটি সামান্য সহায়ক লিখেছি যা ত্রুটির জন্য কিছুটা প্রসঙ্গ দেয়:

আমরা লাইনটির জন্য স্ক্রিপ্টটি পরিদর্শন করতে পারি যা ব্যর্থতার কারণ হয়েছিল:

err() {
    echo "Error occurred:"
    awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0
}
trap 'err $LINENO' ERR

এটি এটি একটি ছোট পরীক্ষার স্ক্রিপ্টে রয়েছে:

#!/bin/bash

set -e

err() {
    echo "Error occurred:"
    awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0
}
trap 'err $LINENO' ERR

echo one
echo two
echo three
echo four
false
echo five
echo six
echo seven
echo eight

আমরা এটি চালানোর সময় আমরা পাই:

$ /tmp/test.sh
one
two
three
four
Error occurred:
12      echo two
13      echo three
14      echo four
15   >>>false
16      echo five
17      echo six
18      echo seven

এটি $(caller)ব্যর্থতা বর্তমান স্ক্রিপ্টে না থাকলেও এর অন্যতম আমদানি প্রসঙ্গটি দেওয়ার জন্য এর ডেটা ব্যবহার করা আরও ভাল । খুব সুন্দর যদিও!
ট্রাইসেস

2

অন্যান্য উত্তরের দ্বারা অনুপ্রাণিত হয়ে এখানে একটি সহজ প্রাসঙ্গিক ত্রুটি হ্যান্ডলার:

trap '>&2 echo Command failed: $(tail -n+$LINENO $0 | head -n1)' ERR

প্রয়োজনে আপনি লেজ ও মাথার পরিবর্তে বিশ্রী ব্যবহার করতে পারেন।


1
অন্য উত্তরটি আপত্তিজনক লাইনের উপরে 3 লাইন এবং 3 লাইন দিয়ে প্রসঙ্গ সরবরাহ করার কারণ রয়েছে - যদি ত্রুটিটি একটি ধারাবাহিকতা রেখা থেকে উদ্ভূত হয়?
ইরুবার

@iruvar এটি বোঝা গেছে, তবে আমার অতিরিক্ত অতিরিক্ত প্রসঙ্গে কোনও দরকার নেই; প্রসঙ্গের একটি লাইন যতটা সহজ হয় ততই সহজ এবং আমার যতটা প্রয়োজন
সান্মই

ঠিক আছে আমার বন্ধু, + 1
ইরুবার

1

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

পঠনযোগ্যতার জন্য এটি এখানে দুটি লাইন হিসাবে দেখানো হচ্ছে - আপনি যদি পছন্দ করেন (সংরক্ষণ করুন ;) তবে আপনি এই লাইনে একটিতে যুক্ত হতে পারেন :

trap 'echo >&2 "Error - exited with status $? at line $LINENO:"; 
         pr -tn $0 | tail -n+$((LINENO - 3)) | head -n7' ERR

এটি set -euo pipefail( আনঅফিসিয়াল কড়া মোড ) দিয়ে বেশ ভাল কাজ করে - কোনও অপরিজ্ঞাত পরিবর্তনশীল ত্রুটি ERRসিউডো-সিগন্যালকে গুলি না করে একটি লাইন নম্বর দেয় তবে অন্যান্য ক্ষেত্রে প্রসঙ্গটি দেখায় show

উদাহরণ আউটপুট:

myscript.sh: line 27: blah: command not found
Error - exited with status 127 at line 27:
   24   # Do something
   25   lines=$(wc -l /etc/passwd)
   26   # More stuff
   27   blah
   28   
   29   # Check time
   30   time=$(date)

0

ইআরআর সিগন্যালটি কোন রেখা থেকে পাঠানো হয়েছিল তা পাওয়া সম্ভব?

হ্যাঁ, LINENOএবং BASH_LINENOভেরিয়েবলগুলি ব্যর্থতার লাইন এবং এটির দিকে নিয়ে যাওয়া লাইনগুলি পাওয়ার জন্য উপকারী er

বা সম্ভবত আমি এই সব ভুল করছি?

নাহ, গ্রেপ -qসহ সবেমাত্র বিকল্প অনুপস্থিত ...

echo hello | grep -q "asdf"

... -qবিকল্পের জন্য এবং জন্য grepফিরে আসবে । এবং বাশে এটা না ...0true1falsetrapTrap

trap "_func" ERR

... আমার একটি দেশীয় সমাধান দরকার ...

এখানে এমন একটি ট্র্যাপার রয়েছে যা আপনি কিছুটা সাইক্লোমেটিক জটিলতায় ডিবাগ করার জন্য দরকারী খুঁজে পেতে পারেন ...

failure.sh

## Outputs Front-Mater formatted failures for functions not returning 0
## Use the following line after sourcing this file to set failure trap
##    trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
failure(){
    local -n _lineno="${1:-LINENO}"
    local -n _bash_lineno="${2:-BASH_LINENO}"
    local _last_command="${3:-${BASH_COMMAND}}"
    local _code="${4:-0}"

    ## Workaround for read EOF combo tripping traps
    if ! ((_code)); then
        return "${_code}"
    fi

    local _last_command_height="$(wc -l <<<"${_last_command}")"

    local -a _output_array=()
    _output_array+=(
        '---'
        "lines_history: [${_lineno} ${_bash_lineno[*]}]"
        "function_trace: [${FUNCNAME[*]}]"
        "exit_code: ${_code}"
    )

    if [[ "${#BASH_SOURCE[@]}" -gt '1' ]]; then
        _output_array+=('source_trace:')
        for _item in "${BASH_SOURCE[@]}"; do
            _output_array+=("  - ${_item}")
        done
    else
        _output_array+=("source_trace: [${BASH_SOURCE[*]}]")
    fi

    if [[ "${_last_command_height}" -gt '1' ]]; then
        _output_array+=(
            'last_command: ->'
            "${_last_command}"
        )
    else
        _output_array+=("last_command: ${_last_command}")
    fi

    _output_array+=('---')
    printf '%s\n' "${_output_array[@]}" >&2
    exit ${_code}
}

... এবং কার্যকারিতা ট্রেসিংয়ের জন্য উপরের ফাঁদটি কীভাবে সেট করবেন সে ক্ষেত্রে সূক্ষ্ম পার্থক্য প্রকাশ করার জন্য উদাহরণ ব্যবহারের স্ক্রিপ্ট ...

example_usage.sh

#!/usr/bin/env bash

set -E -o functrace

## Optional, but recommended to find true directory this script resides in
__SOURCE__="${BASH_SOURCE[0]}"
while [[ -h "${__SOURCE__}" ]]; do
    __SOURCE__="$(find "${__SOURCE__}" -type l -ls | sed -n 's@^.* -> \(.*\)@\1@p')"
done
__DIR__="$(cd -P "$(dirname "${__SOURCE__}")" && pwd)"


## Source module code within this script
source "${__DIR__}/modules/trap-failure/failure.sh"

trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR


something_functional() {
    _req_arg_one="${1:?something_functional needs two arguments, missing the first already}"
    _opt_arg_one="${2:-SPAM}"
    _opt_arg_two="${3:0}"
    printf 'something_functional: %s %s %s' "${_req_arg_one}" "${_opt_arg_one}" "${_opt_arg_two}"
    ## Generate an error by calling nothing
    "${__DIR__}/nothing.sh"
}


## Ignoring errors prevents trap from being triggered
something_functional || echo "Ignored something_functional returning $?"
if [[ "$(something_functional 'Spam!?')" == '0' ]]; then
    printf 'Nothing somehow was something?!\n' >&2 && exit 1
fi


## And generating an error state will cause the trap to _trace_ it
something_functional '' 'spam' 'Jam'

উপরের যেখানে বাশ সংস্করণ 4+ তে পরীক্ষা করা হয়েছে, সুতরাং চারটি পূর্বের সংস্করণগুলির জন্য কিছু প্রয়োজন হলে একটি মন্তব্য দিন বা যদি নূন্যতম সংস্করণের চারটি সিস্টেমে ব্যর্থতা আটকাতে ব্যর্থ হয় তবে একটি সমস্যা খুলুন

প্রধান অবলম্বন হ'ল ...

set -E -o functrace
  • -Eবুদ্বুদ আপ ফাংশন মধ্যে ত্রুটি ঘটায়

  • -o functrace যখন কোনও ক্রিয়াকলাপের মধ্যে কিছু ব্যর্থ হয় তখন কারণগুলি আরও ভার্বোসটি করতে দেয়

trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
  • একক উদ্ধৃতি ফাংশন কল এবং চারপাশে ডাবল উদ্ধৃতি পৃথক যুক্তি প্রায় ব্যবহৃত হয়

  • বর্তমান মানগুলির পরিবর্তে রেফারেন্সগুলি LINENOএবং BASH_LINENOপাস করা হয়, যদিও এটি ফাঁদে যুক্ত লিঙ্কের পরবর্তী সংস্করণগুলিতে ছোট করা যেতে পারে, যেমন চূড়ান্ত ব্যর্থতার রেখা এটিকে আউটপুটে পরিণত করে

  • প্রথমে কোনও ত্রুটি ফিরে পেয়েছিল এমন কমান্ড পাওয়ার জন্য প্রথমে BASH_COMMANDএবং প্রস্থান স্থিতির মানগুলি ( $?) পাস হয়ে যায় এবং দ্বিতীয়টি নিশ্চিত করা যায় যে ত্রুটিটি অ-ত্রুটিযুক্ত স্থিতিতে ট্র্যাপটি ট্রিগার করে না does

এবং অন্যরা মতানৈক্য করতে পারলে আমি আউটপুট অ্যারে তৈরি করা এবং নিজের লাইনে প্রতিটি অ্যারে উপাদান মুদ্রণের জন্য প্রিন্টফ ব্যবহার করা আরও সহজ ...

printf '%s\n' "${_output_array[@]}" >&2

... >&2শেষে কিছুটা হলেও ত্রুটিগুলি যেখানে তাদের উচিত (স্ট্যান্ডার্ড ত্রুটি) হওয়া উচিত, এবং কেবল ত্রুটিগুলি ক্যাপচার করার অনুমতি দেয় ...

## ... to a file...
some_trapped_script.sh 2>some_trapped_errros.log

## ... or by ignoring standard out...
some_trapped_script.sh 1>/dev/null

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

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