Đăng nhập mã thoát lệnh, tương tự lệnh thời gian


10

sử dụng

time sleep 1

sản lượng:

$ time sleep 1

real    0m1.005s
user    0m0.001s
sys     0m0.001s

Có một lệnh tôi có thể sử dụng để in mã thoát sleephoặc bất kỳ lệnh nào tôi muốn chạy không?

Một cái gì đó thích:

$ log-exit-code sleep 1

Có lẽ điều này là đủ?

sleep 1 && echo "$?"

3
Không, sleep 1 && echo $?sẽ chỉ in mã của tế bào ngủ khi nó bằng không ...
Satō Katsura

oh lol bạn nói đúng
Alexander Mills

1
sleep 1 && echo "$?" || echo "$?"
jesse_b

2
Tôi đã thêm một câu trả lời vì tất cả các câu trả lời khác cho đến nay đều loại bỏ giá trị trả về ban đầu, mà imo là xấu (sau những câu trả lời đó, $? Luôn là 0 vì điều cuối cùng chúng làm là một từ chối, luôn luôn hoạt động. giá trị trả về ban đầu và trả về sau khi hiển thị nó. Do đó, họ chỉ hiển thị nó cho người quan sát, nhưng 'ẩn' nó cho phần còn lại của tập lệnh, hiện không thể sử dụng "$?" để xem liệu lệnh quan trọng đó có trả về không 0 hoặc một cái gì đó khác ...)
Olivier Dulac

1
Ngoài ra tất cả các giải pháp dưới đây có thể dễ dàng thực hiện chức năng này. Ví dụ của Kusalananda sẽ là:EXIT_CODE=$(tellexit command)
jesse_b

Câu trả lời:


4

Trong thử nghiệm của tôi cho đến nay điều này đã làm việc:

command && echo "$?" || echo "$?"

Chỉ cần nói với nó để lặp lại mã thoát nếu nó thành công hoặc nếu nó thất bại.

Như Sato đã chỉ ra bên dưới, điều này về cơ bản giống như:

command; echo "$?"

Một điều có thể làm cho lệnh và / hoặc đáng giá là một cái gì đó như:

command && echo "Success! Exit Code: $?" || echo "Failure! Exit Code: $?"

Nếu bạn cần tập lệnh của mình hành động theo mã thoát như mối quan tâm của Olivier, thì đó không phải là vấn đề. Kịch bản của bạn có thể trông giống như:

command
case "$?" in; 
    0) echo "Command exited with: 0"
       <command if good>
       ;;
    1) echo "Command exited with: 1"
        <command if bad>
        ;;
    255) echo "Command exited with: 255"  # for ssh maybe?
         <command if 255>
         ;;
    *) echo "Command exited with: >2"
        <command for other exit code>
        ;;
esac

13
Err, làm thế nào tốt hơn chỉ command; echo $??
Satō Katsura

4
Tôi đoán là không phải. command; echo $?là một câu trả lời tốt hơn nhiều.
jesse_b

uhhh đây có vẻ như là lựa chọn tốt nhất, vì vậy tôi đã chọn nó làm câu trả lời, nếu có ai không đồng ý, lmk
Alexander Mills

@AlexanderMills Chỉ có bạn biết câu trả lời nào phù hợp nhất cho câu hỏi của bạn :-)
Kusalananda

1
Tôi không thích điều này: điều này thay đổi mã thoát sau command ; echo $?echo $?luôn thành công và do đó, sau giá trị mới của $? bây giờ là 0. Có một cách để giữ mã trả về ban đầu ngay cả sau khi hiển thị nó, trong trường hợp mã trả về ban đầu này hữu ích sau này (Ví dụ: trong tập lệnh, kiểm tra mã trả về là quan trọng trước khi quyết định tiếp tục). Xem câu trả lời của tôi cho một trong nhiều giải pháp (hầu hết các câu trả lời ở đây có thể được thay đổi theo cùng một cách)
Olivier Dulac

11

cmd && echo "$?"sẽ không hoạt động vì nó chỉ cần in các số 0 ( echosẽ chỉ thực hiện khi hoàn thành thành công lệnh trước).

Đây là một hàm shell ngắn dành cho bạn:

tellexit () {
    "$@"

    local err="$?"
    printf 'exit code\t%d\n' "$err" >/dev/tty
    return "$err"
}

Điều này in mã thoát của lệnh đã cho theo cách tương tự như timelệnh.

$ tellexit echo "hello world"
hello world
exit code       0

$ tellexit false
exit code       1

Bằng cách chuyển hướng printfđến /dev/ttytrong chức năng, chúng tôi vẫn có thể sử dụng tellexitvới các chuyển hướng mà không nhận được rác trong luồng đầu ra tiêu chuẩn hoặc lỗi:

$ tellexit bash -c 'echo hello; echo world >&2' >out 2>err
exit code       0
$ cat out
hello
$ cat err
world

Bằng cách lưu mã thoát trong một biến, chúng tôi có thể trả lại mã cho người gọi:

$ tellexit false || echo 'failed'
exit code       1
failed

Một phiên bản fancier của cùng chức năng cũng in tín hiệu đã giết lệnh nếu mã thoát lớn hơn 128 (có nghĩa là nó bị chấm dứt do tín hiệu):

tellexit () {
    "$@"

    local err="$?"

    if [ "$err" -gt 128 ]; then
        printf 'exit code\t%d (%s)\n' "$err" "$(kill -l "$err")" >/dev/tty
    else
        printf 'exit code\t%d\n' "$err" >/dev/tty
    fi

    return "$err"
}

Kiểm tra:

$ tellexit sh -c 'kill $$'
exit code       143 (TERM)

$ tellexit sh -c 'kill -9 $$'
Killed
exit code       137 (KILL)

(Điều localnày yêu cầu ash/ pdksh/ bash/ zsh, hoặc bạn có thể thay đổi nó thành typesetmột vài shell khác cũng hiểu.)


tuyệt, bạn sẽ sử dụng tellexit như thế nào, hãy thể hiện nó trong hành động
Alexander Mills

1
@AlexanderMills Xem cập nhật.
Kusalananda

2
Nó sẽ giữ giá trị trả lại ban đầu và trả lại cuối cùng.
Olivier Dulac

@OlivierDulac Quan sát thực sự tốt! Tôi sẽ sửa đổi.
Kusalananda

7

Sử dụng một chức năng bao bọc shell điều. Có lẽ với một cái tên khác.

$ exito() { "$@"; echo $?; }
$ exito true
0
$ exito false
1
$ exito echo "test test"      
test test
0
$ 

(Điều này tất nhiên sẽ làm hỏng đầu ra tiêu chuẩn, do đó, hãy sử dụng ttynhư được hiển thị bởi @Kusalananda hoặc không sử dụng nó bên ngoài bối cảnh tương tác.)

Chuyển sang lãnh thổ không thể di chuyển, một số shell có thể báo cáo về trạng thái của tất cả các lệnh trong một đường ống, không chỉ là lệnh cuối cùng, ví dụ như trong ZSH nếu bạn muốn báo cáo lỗi từ toàn bộ đường ống:

% TRAPZERR() { print >/dev/tty $pipestatus }
% perl -e 'exit 42' | perl -e 'exit 99'
42 99
% false | perl -e 'exit 42' | perl -e 'exit 99'
1 42 99
% perl -e 'exit 42' | perl -e 'exit 99' | true
% 

TRAPZERR mặt khác không kích hoạt khi không có lỗi (trên hiệu trưởng "không có tin nào là tin tốt").


1
Nó sẽ giữ giá trị trả lại ban đầu và trả lại cuối cùng. Hiển thị (printf, echo) một điều đơn giản (không bắt đầu bằng '-', v.v.) luôn hoạt động và sau đó hiển thị "$?" hiện có giá trị "0" khi màn hình hoạt động
Olivier Dulac

7

GNU timecó một tùy chọn cho việc này:

time -f %x sleep 1
0

Chuyển qua mã thoát 1 , trừ khi bị giết bởi tín hiệu 2 :

$ /usr/bin/time -f %x sleep 1; echo $?
0
0

$ /usr/bin/time -f %x sleep 2x; echo $?
sleep: invalid time interval ‘2x’
Try 'sleep --help' for more information.
1
1

$ /usr/bin/time -f %x sleep 60s; echo $? # Press ^C before a minute elapses
0
2

Nếu bạn muốn biết / xử lý tình huống tiêu diệt tín hiệu, hãy vượt qua -vvà grep stderr cho chuỗi Command terminated by signal.


1 Cảm ơn Olivier Dulac vì đã lưu ý mã thoát đi qua.
2 Ngoài ra, cảm ơn bạn Stéphane Chazelas vì đã chỉ ra mã thoát tín hiệu tiêu diệt không đi qua.


1
Can thiệp. GNU chỉ nhưng can thiệp, vì người ta sẽ (có thể) giữ mã trả lại ban đầu cho phần còn lại của mã để theo dõi (nghĩa là nó không thay thế nó bằng "0" như các câu trả lời khác làm)
Olivier Dulac

2
Nó trả về 0mặc dù lệnh bị giết.
Stéphane Chazelas

2
@bishop, tôi đồng ý 0 trong những trường hợp đó là ít hơn lý tưởng. Nhưng lưu ý rằng, không có thỏa thuận chung nào về việc phải báo cáo gì khi lệnh bị giết bởi tín hiệu. Trả lại số tín hiệu 128 + được sử dụng bởi một vài vỏ. Bạn cũng thấy những thứ như 256+signumhoặc 384+signumthậm chí signum/256hoặc signum/256+0.5nếu một lõi được tạo ra (thực tế trạng thái được trả về waitpid()chia cho 256). Một số sẽ đưa ra một đại diện văn bản (như siginthoặc sigquit+core). Tôi vẫn có thể thảo luận về nhóm tin tức gnu.coreutils.bugs.
Stéphane Chazelas

3
(thực sự timekhông phải là một phần của coreutils, nó là một gói riêng với danh sách gửi thư lỗi của riêng nó (bug-time@gnu.org))
Stéphane Chazelas

1
@bishop, các system()awks truyền thống như vẫn được duy trì bởi Brian Kernighan (người kawk) hoặc nawkSolaris, awkFreeBSD bắt nguồn từ đó. awk 'BEGIN{print system("kill -s ABRT $$")}'đầu ra 0.523438khi kích thước bãi chứa lõi không bị giới hạn. Hành vi của gawkđã thay đổi gần đây, với hành vi khác nhau với --traditionalhoặc --posix(xem thêm giá trị trả về của close(cmd)biến thể khác)
Stéphane Chazelas

2

Tôi không thích tất cả các câu trả lời khác (mặc dù tôi rất thích sự thông minh của họ): họ hiển thị mã thoát nhưng họ cũng THAY ĐỔI CNTT. (phần hiển thị là đúng, do đó sau đó mã trả về là 0)

Đây là một phiên bản sửa đổi:

do_and_tell () {
   "$@"
   returncode="$?"
   printf "Execution of : \n%s\n yelded a return code of: \n%s\n" "$*" "$returncode"
   return $returncode  # the interresting addition... keeps the commands return value.
}

## usage:

prompt$ do_and_tell true
Execution of : 
true
 yelded a return code of: 
0

prompt$ echo $?
0

prompt$ do_and_tell false
Execution of : 
false
 yelded a return code of: 
1

prompt$ echo $?
1

thực ra, câu trả lời @bishop là câu trả lời duy nhất khác giữ giá trị này, nhưng không dựa vào phiên bản GNU timekhông có sẵn.
Olivier Dulac

2

Để mạnh mẽ hơn một chút, hãy gửi trạng thái thoát tới một FD riêng để nó có thể được xử lý độc lập với thiết bị xuất chuẩn / stderr:

exit_status() {
    "$@"
    rv=$?
    echo >&3 "$rv"
    return "$rv"
}

# exit status and stdout to stdout:
> exit_status echo "hello" 3>&1
hello
0

# exit_status to stdout, stdout to /dev/null
> exit_status echo "hello" 3>&1 1>/dev/null
0
> exit_status ehco "hello" 3>&1 1>/dev/null
ehco: command not found
127

# exit_status to stdout, stdout and stderr to /dev/null
> exit_status ehco "hello" 3>&1 &>/dev/null
127

Lưu ý bạn sẽ cần phải làm gì đó với FD3 hoặc nó sẽ nói Bad file descriptor.

Điều này có thể được cấu hình hơn nữa để cung cấp các đầu ra này cho đầu vào của một chương trình khác bằng cách cho chương trình kia nghe trên nhiều FD; bạn có thể sử dụng nó như một loại Kibana đầu thập niên 90 :)


Nó sẽ giữ giá trị trả lại ban đầu và trả lại cuối cùng. Hiển thị (printf, echo) một điều đơn giản (không bắt đầu bằng '-', v.v.) luôn hoạt động và sau đó hiển thị "$?" hiện có giá trị "0" khi màn hình hoạt động
Olivier Dulac

1

Trong khi tất cả các câu trả lời khác (rất thú vị) giải quyết chính xác câu hỏi mà OP đã hỏi, trong thực tế, mọi thứ thường đơn giản hơn. Bạn chỉ cần lưu trạng thái thoát vào một biến (ngay sau lệnh) và báo cáo hoặc ghi nhật ký theo bất kỳ cách nào bạn muốn. Ví dụ: in ra / dev / stderr hoặc viết / nối nó dưới dạng tin nhắn văn bản vào tệp nhật ký. Và, nó cũng được bảo quản để sử dụng trong việc ra quyết định / kiểm soát luồng trong mã tiếp theo.

Nếu đó là trong một chức năng:

function some-function () {
    local rc ## to avoid side effects
    ...
    some-command ## run any command
    rc=$?  ## save the return status in a variable
    echo "some-command returned $rc" ## optionally tell the user about it
    ...
    return $rc  ## at the end, if appropriate
}

Nếu nó trực tiếp trong một kịch bản:

some-command ## run any command
rc=$?  ## save the return status in a variable
echo "some-command returned $rc" ## optionally tell the user about it
...
exit $rc    ## at the end to tell any calling script about it, if appropriate

(Vịt và che vì điều này không trả lời chính xác câu hỏi.)

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.