ngữ cảnh gọi hàm của hàm trong zsh: tương đương với bash `caller`


8

Trong bash, tôi có thể viết:

caller 0

và nhận bối cảnh của người gọi :

  • Số dòng
  • Chức năng
  • Tên tập lệnh

Điều này cực kỳ hữu ích để gỡ lỗi. Được:

yelp () { caller 0; }

Sau đó tôi có thể viết yelpđể xem những dòng mã nào đang đạt được.

Tôi có thể thực hiện caller 0tại bashnhư:

echo "${BASH_LINENO[0]} ${FUNCNAME[1]} ${BASH_SOURCE[1]"

Làm thế nào tôi có thể nhận được cùng một đầu ra như caller 0trong zsh?

Câu trả lời:


14

Tôi không nghĩ có một lệnh dựng sẵn tương đương, nhưng một số kết hợp của bốn biến này từ mô-đun zsh / Parameter có thể được sử dụng:

funcfiletrace

Mảng này chứa số dòng tuyệt đối và tên tệp tương ứng cho điểm mà hàm hiện tại, tệp có nguồn gốc hoặc lệnh (nếu EVAL_LINENOđược đặt) evalđược gọi. Mảng có cùng độ dài funcsourcetracefunctrace, nhưng khác funcsourcetraceở chỗ dòng và tệp là điểm gọi, không phải là điểm định nghĩa và khác với functracetất cả các giá trị là số dòng tuyệt đối trong tệp, thay vì liên quan đến bắt đầu một chức năng, nếu có.

funcsourcetrace

Mảng này chứa tên tệp và số dòng của các điểm trong đó các hàm, tệp có nguồn gốc và các lệnh (nếu EVAL_LINENOđược đặt) evalhiện đang được thực thi đã được xác định. Số dòng là dòng bắt đầu ' function name' hoặc ' name ()'. Trong trường hợp chức năng tự động tải, số dòng được báo cáo là 0. Định dạng của mỗi yếu tố là filename:lineno.

Đối với các chức năng được tự động tải từ một tệp ở định dạng zsh gốc, trong đó chỉ có phần thân của hàm xảy ra trong tệp hoặc đối với các tệp đã được thực thi bởi các nội dung sourcehoặc ' .', thông tin theo dõi được hiển thị dưới dạng filename:0, vì toàn bộ tệp là Định nghĩa. Tên tệp nguồn được phân giải thành một đường dẫn tuyệt đối khi hàm được tải hoặc đường dẫn đến nó được giải quyết theo cách khác.

funcfiletraceThay vào đó, hầu hết người dùng sẽ quan tâm đến thông tin trong mảng.

funcstack

Mảng này chứa tên của các hàm, tệp có nguồn gốc và các lệnh (nếu EVAL_LINENOđược đặt) eval. hiện đang được thực thi. Phần tử đầu tiên là tên của hàm sử dụng tham số.

Mảng shell tiêu chuẩn zsh_eval_contextcó thể được sử dụng để xác định loại cấu trúc shell đang được thực hiện ở mỗi độ sâu: tuy nhiên, lưu ý là theo thứ tự ngược lại, với mục gần đây nhất cuối cùng và chi tiết hơn, ví dụ như bao gồm một mục cho toplevel, mã shell chính đang được thực thi hoặc tương tác hoặc từ một tập lệnh, không có trong $funcstack.

functrace

Mảng này chứa tên và số dòng của người gọi tương ứng với các chức năng hiện đang được thực thi. Định dạng của mỗi yếu tố là name:lineno. Người gọi cũng được hiển thị cho các tập tin có nguồn gốc; người gọi là điểm nơi sourcehoặc ' .lệnh' bị xử tử.

So sánh:

foo.bash:

#! /bin/bash
yelp() {
    caller 0
}

foo () {
    yelp
}

foo

foo.zsh:

#! /bin/zsh
yelp() {
    print -l -- $funcfiletrace - $funcsourcetrace - $funcstack - $functrace
}

foo () {
    yelp
}

foo

Kết quả:

$ bash foo.bash
7 foo foo.bash

$ zsh foo.zsh
foo.zsh:7
foo.zsh:10
-
foo.zsh:2
foo.zsh:6
-
yelp
foo
-
foo:1
foo.zsh:10

Vì vậy, các giá trị tương ứng là trong ${funcfiletrace[1]}${funcstack[-1]}. Sửa đổi yelpthành:

yelp() {
    print -- $funcfiletrace[1] $funcstack[-1]
}

Đầu ra là:

foo.zsh:7 foo

khá gần với bash

7 foo foo.bash

3

Dựa trên câu trả lời của muru , tôi đã thực hiện chức năng sau hoạt động trong cả hai {ba,z}sh:

$ cat yelp
#!/bin/zsh
# Say the file, line number and optional message for debugging
# Inspired by bash's `caller` builtin
# Thanks to https://unix.stackexchange.com/a/453153/143394
function yelp () {
  # shellcheck disable=SC2154  # undeclared zsh variables in bash
  if [[ $BASH_VERSION ]]; then
    local file=${BASH_SOURCE[1]} func=${FUNCNAME[1]} line=${BASH_LINENO[0]}
  else  # zsh
    emulate -L zsh  # because we may be sourced by zsh `emulate bash -c`
    # $funcfiletrace has format:  file:line
    local file=${funcfiletrace[1]%:*} line=${funcfiletrace[1]##*:}
    local func=${funcstack[2]}
    [[ $func =~ / ]] && func=source  # $func may be filename. Use bash behaviour
  fi
  echo "${file##*/}:$func:$line $*" > /dev/tty
}

foo () { yelp; }
yelp
foo

Đầu ra là:

$ ./yelp
yelp::20 
yelp:foo:19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.