Làm cách nào để chạy một hàm từ một tập lệnh trong dòng lệnh?


119

Tôi có một tập lệnh có một số chức năng.

Tôi có thể chạy một trong các chức năng trực tiếp từ dòng lệnh không?

Một cái gì đó như thế này?

myScript.sh func()

Câu trả lời:


66

Nếu tập lệnh chỉ xác định các chức năng và không làm gì khác, trước tiên bạn có thể thực thi tập lệnh trong ngữ cảnh của trình bao hiện tại bằng cách sử dụng lệnh sourcehoặc .và sau đó chỉ cần gọi hàm. Xem help sourceđể biết thêm thông tin.


1
Vấn đề duy nhất với phương pháp này là nếu bạn sử dụng exittrong hàm của mình, nó sẽ đóng thiết bị đầu cuối sau khi hàm được thực thi. Có cách nào để khắc phục điều này? @SvenMarnach
dùng1527227

@ user1527227: Đi với câu trả lời tiếp theo trong trường hợp đó, vì bạn có quyền kiểm soát tập lệnh shell. Nếu không, bạn có thể gọi một vỏ con tương tác trước (chỉ cần nhập bash) và exitsẽ chỉ kết thúc vỏ con chứ không phải thiết bị đầu cuối của bạn.
Sven Marnach

238

Chà, trong khi các câu trả lời khác đều đúng - bạn chắc chắn có thể làm điều gì đó khác: nếu bạn có quyền truy cập vào tập lệnh bash, bạn có thể sửa đổi nó và chỉ cần đặt ở cuối tham số đặc biệt "$@"- sẽ mở rộng đến các đối số của dòng lệnh bạn chỉ định, và vì nó là "một mình" nên shell sẽ cố gắng gọi chúng một cách nguyên văn; và ở đây bạn có thể chỉ định tên hàm làm đối số đầu tiên. Thí dụ:

$ cat test.sh
testA() {
  echo "TEST A $1";
}

testB() {
  echo "TEST B $2";
}

"$@"


$ bash test.sh
$ bash test.sh testA
TEST A 
$ bash test.sh testA arg1 arg2
TEST A arg1
$ bash test.sh testB arg1 arg2
TEST B arg2

Để đánh bóng, trước tiên bạn có thể xác minh rằng lệnh tồn tại và là một hàm:

# Check if the function exists (bash specific)
if declare -f "$1" > /dev/null
then
  # call arguments verbatim
  "$@"
else
  # Show a helpful error
  echo "'$1' is not a known function name" >&2
  exit 1
fi

16
Sử dụng "$@"trong hầu hết các trường hợp. $@không an toàn trong một số trường hợp.
fumiyas

1
Làm thế nào để chạy nhiều hơn một chức năng? ví dụ tôi có thể chạy bash test.sh testA testBkhông?
Jeff Pang

Điều này cũng cần phải được bao bọc bởi [ ! -z "$1" ]nếu không thì nguồn sẽ nâng cao các báo cáo khác trong một số verions bash
JackLeo

Tôi đã tìm kiếm gần xa cho biến "$ @" kỳ diệu này để sử dụng bất kỳ hàm nào được gọi trong tệp, cảm ơn bạn @sdaau!
Justin Hammond

36

Lệnh sau đây đầu tiên đăng ký hàm trong ngữ cảnh, sau đó gọi nó:

. ./myScript.sh && function_name

1
Bạn cũng có thể đơn giản sử dụng nguồn. Như trong - nguồn myScript.sh && function_name
steve_leaves

17

Một cách ngắn gọn, không.

Bạn có thể nhập tất cả các hàm trong tập lệnh vào môi trường của mình với source( help sourceđể biết chi tiết), sau đó sẽ cho phép bạn gọi chúng. Điều này cũng có ảnh hưởng đến việc thực thi script, vì vậy hãy cẩn thận.

Không có cách nào để gọi một hàm từ tập lệnh shell như thể nó là một thư viện được chia sẻ.


1
Tôi nghĩ điều này nên được coi trọng hơn như một câu trả lời thích hợp. Tôi đã cố gắng làm điều gì đó tương tự như những gì OP đang muốn, nhưng kịch bản shell đơn giản là không được thiết kế để "phát triển OOP, sạch" (IMHO).
Dan L

4

Sử dụng case

#!/bin/bash

fun1 () {
    echo "run function1"
    [[ "$@" ]] && echo "options: $@"
}

fun2 () {
    echo "run function2"
    [[ "$@" ]] && echo "options: $@"
}

case $1 in
    fun1) "$@"; exit;;
    fun2) "$@"; exit;;
esac

fun1
fun2

Tập lệnh này sẽ chạy các hàm fun1 và fun2 nhưng nếu bạn khởi động nó với tùy chọn fun1 hoặc fun2, nó sẽ chỉ chạy hàm đã cho với args (nếu được cung cấp) và thoát. Sử dụng

$ ./test 
run function1
run function2

$ ./test fun2 a b c
run function2
options: a b c

1

Chỉnh sửa: CẢNH BÁO - có vẻ như điều này không hoạt động trong mọi trường hợp, nhưng hoạt động tốt trên nhiều tập lệnh công khai.

Nếu bạn có một tập lệnh bash được gọi là "control" và bên trong nó, bạn có một chức năng được gọi là "build":

function build() { 
  ... 
}

Sau đó, bạn có thể gọi nó như thế này (từ thư mục ở đó):

./control build

Nếu nó nằm trong một thư mục khác, điều đó sẽ làm cho nó:

another_folder/control build

Nếu tệp của bạn được gọi là "control.sh", điều đó sẽ làm cho hàm có thể gọi được như sau:

./control.sh build

1
Điều này không hoạt động trong trình bao tương tác đối với tôi. Nhưng điều này đã hiệu quả:. ./control.sh && build
saulius 2

1

Tôi có một tình huống mà tôi cần một hàm từ tập lệnh bash không được thực thi trước (ví dụ: bởi source) và vấn đề với @$myScript.sh sau đó được chạy hai lần, có vẻ như ... Vì vậy, tôi đã nảy ra ý tưởng để lấy chức năng ra với sed:

sed -n "/^func ()/,/^}/p" myScript.sh

Và để thực thi nó vào lúc tôi cần, tôi đặt nó vào một tệp và sử dụng source:

sed -n "/^func ()/,/^}/p" myScript.sh > func.sh; source func.sh; rm func.sh


0

bạn có thể gọi hàm từ đối số dòng lệnh như bên dưới

function irfan() {
echo "Irfan khan"
date
hostname
}
function config() {
ifconfig
echo "hey"
}
$1

khi bạn kết thúc hàm, hãy đặt $ 1 để chấp nhận đối số, giả sử mã ở trên được lưu trong fun.sh để chạy hàm ./fun.sh irfan & ./fun.sh config


0

Bài đã giải quyết nhưng tôi muốn đề cập đến giải pháp ưa thích của mình. Cụ thể, xác định một tập lệnh một lớp lót chung eval_func.sh:

#!/bin/bash
source $1 && shift && "@a"

Sau đó gọi bất kỳ hàm nào trong bất kỳ tập lệnh nào qua:

./eval_func.sh <any script> <any function> <any args>...

Một vấn đề tôi gặp phải với giải pháp được chấp nhận là khi tìm nguồn cung cấp tập lệnh chứa hàm của tôi trong một tập lệnh khác, các đối số của tập lệnh sau sẽ được đánh giá bởi tập lệnh trước, gây ra lỗ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.