Làm thế nào để trả lại mã thoát? Lỗi: return: Đọc: yêu cầu đối số


7

Đây là một phiên bản đơn giản hóa của kịch bản của tôi. Câu hỏi của tôi là, làm thế nào để tôi trả lại mã thoát apt-gettrong trường hợp này?

#!/bin/bash
install_auto() {
apt-get -h > /dev/null 2>&1
if [ $? -eq 0 ] ; then
    return $(sudo apt-get install --assume-yes $@)
fi
return 1
}
echo "installing $@"
install_auto "$@"
echo $?
echo "finished"
exit 0

Đầu ra là:

./install_test.sh: line 5: return: Reading: numeric argument required

Cập nhật: Tôi đã đưa ra một cái gì đó hoạt động:

return $(sudo apt-get install --assume-yes "$@" >/dev/null 2>&1; echo $?)

Đó có phải là một cách tiếp cận tốt?

Câu trả lời:


7

Bash's return()chỉ có thể trả về các đối số số. Trong mọi trường hợp, theo mặc định, nó sẽ trả về trạng thái thoát của lệnh chạy cuối cùng. Vì vậy, tất cả những gì bạn thực sự cần là:

#!/usr/bin/env bash
install_auto() {
apt-get -h > /dev/null 2>&1
if [ $? -eq 0 ] ; then
    sudo apt-get install --assume-yes $@
fi
}

Bạn không cần phải thiết lập một giá trị được trả về một cách rõ ràng vì theo mặc định, một hàm sẽ trả về $?. Tuy nhiên, điều đó sẽ không hoạt động nếu aptlệnh đầu tiên thất bại và bạn không đi vào ifvòng lặp. Để làm cho nó mạnh mẽ hơn, sử dụng này:

#!/usr/bin/env bash
install_auto() {
apt-get -h > /dev/null 2>&1
ret=$?
if [ $ret -eq 0 ] ; then
    ## If this is executed, the else is ignored and $? will be
    ## returned. Here, $?will be the exit status of this command
    sudo apt-get install --assume-yes $@
else
    ## Else, return the exit value of the first apt-get
    return $ret
fi
}

Nguyên tắc chung là để có một hàm trả về trạng thái thoát của một công việc cụ thể và không nhất thiết là công việc cuối cùng mà nó đã chạy, bạn sẽ cần lưu trạng thái thoát vào một biến và trả về biến:

function foo() {
    run_a_command arg1 arg2 argN
    ## Save the command's exit status into a variable
    return_value= $?

    [the rest of the function  goes here]
    ## return the variable
    return $return_value
}

EDIT: Trên thực tế, như @gniourf_gniourf đã chỉ ra trong các bình luận, bạn có thể đơn giản hóa rất nhiều toàn bộ bằng cách sử dụng &&:

install_auto() {
  apt-get -h > /dev/null 2>&1 &&
  sudo apt-get install --assume-yes $@
}

Giá trị trả về của hàm này sẽ là một trong:

  1. Nếu apt-get -h thất bại, nó sẽ trả về mã thoát của nó
  2. Nếu apt-get -hthành công, nó sẽ trả về mã thoát của sudo apt-get install.

Xin lỗi, ví dụ của tôi không đủ rõ ràng. Tôi cần một câu lệnh return (hoặc một số logic tương đương) trong tập lệnh thực tế của tôi để những thứ theo sau câu lệnh này không được thực thi nếu apt-get có mặt trên hệ thống này. Nếu apt-get không có mặt, nó sẽ tìm zypper, v.v. Tôi đoán việc thêm return $?vào dòng tiếp theo của ví dụ của bạn sau sudo apt-get ...có thể là đủ. Có đúng không? Cảm ơn
MountainX

@MaxX xem câu trả lời cập nhật. Cách bạn đã viết nó (và cách tôi đã viết ví dụ của mình) nếu aptthất bại, thì trạng thái thoát của nó được trả về và hàm thoát, trả về giá trị thoát của at-get. Đó không phải là những gì bạn cần?
terdon

2
các retbiến là vô ích. apt-get -h > /dev/null 2>&1 && sudo apt-get install --assume-yes "$@"sẽ làm như vậy. Ồ, và sử dụng nhiều trích dẫn hơn, đặc biệt là cho$@
gniourf_gniourf

@gniourf_gniourf đúng vậy, trả lời cập nhật.
terdon

Cảm ơn vì bạn đã phản hồi. Tôi đã dán chức năng hoàn chỉnh của mình khi tôi nhận ra rằng ví dụ đơn giản hóa của mình là không đủ. Tôi đánh giá cao bất kỳ ý kiến ​​thêm.
MountainX

1

Để hoàn thiện, đây là chức năng thực tế của tôi với một số sửa đổi theo đề xuất của @terdon và @gniourf_gniourf:

install_auto() {
    if [ ! $# -gt 0 ] ; then
        echo "usage: $0 package_name [package_name ...]"
    fi 

    apt-get -h > /dev/null 2>&1
    if [ $? -eq 0 ] ; then
        if [ -f "$@" ] || [[ "$@" =~ '/' ]] ; then
            sudo gdebi -n "$@"
            return $?
        else    
            sudo apt-get install --assume-yes "$@"
            return $?
        fi
    fi

    zypper help > /dev/null 2>&1
    if [ $? -eq 0 ] ; then
            sudo zypper --non-interactive --no-gpg-checks --quiet install --auto-agree-with-licenses "$@"
            return $?
    fi

    #may check other package managers in the future

    echo "ERROR: package manager not found"
    return 255
}

Tôi đánh giá cao bất kỳ đề nghị thêm.


Cấu cmd; if [ $? -eq 0 ]; then ...trúc nói chung được thể hiện tốt hơn if cmd; then ...hoặc thậm chí chỉ cmd && ...khi phần "thì" chỉ là một lệnh đơn giản.
tripleee
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.