ฉันจะเรียกใช้ฟังก์ชันจากสคริปต์ในบรรทัดคำสั่งได้อย่างไร


119

ฉันมีสคริปต์ที่มีฟังก์ชันบางอย่าง

ฉันสามารถเรียกใช้หนึ่งในฟังก์ชันโดยตรงจากบรรทัดคำสั่งได้หรือไม่?

อะไรทำนองนี้?

myScript.sh func()

คำตอบ:


66

หากสคริปต์กำหนดเฉพาะฟังก์ชันและไม่ดำเนินการอื่นใดก่อนอื่นคุณสามารถเรียกใช้สคริปต์ภายในบริบทของเชลล์ปัจจุบันโดยใช้คำสั่งsourceหรือ.จากนั้นเรียกใช้ฟังก์ชัน ดูhelp sourceข้อมูลเพิ่มเติม


1
ปัญหาเดียวของวิธีนี้คือถ้าคุณใช้exitในฟังก์ชันของคุณมันจะปิดเทอร์มินัลหลังจากที่ฟังก์ชันทำงาน มีวิธีแก้ปัญหานี้หรือไม่? @SvenMarnach
user1527227

@ user1527227: ไปกับคำตอบถัดไปในกรณีนั้นเนื่องจากคุณสามารถควบคุมเชลล์สคริปต์ได้ หากไม่เป็นเช่นนั้นคุณสามารถเรียก subshell แบบโต้ตอบได้ก่อน (เพียงแค่ป้อนbash) และexitจะยุติเฉพาะ subshell แต่ไม่ใช่เทอร์มินัลของคุณ
Sven Marnach

238

ในขณะที่คำตอบอื่น ๆ นั้นถูกต้อง - คุณสามารถทำอย่างอื่นได้อย่างแน่นอน: หากคุณมีสิทธิ์เข้าถึงสคริปต์ทุบตีคุณสามารถแก้ไขได้และวางไว้ที่ท้ายพารามิเตอร์พิเศษ"$@"ซึ่งจะขยายไปยังอาร์กิวเมนต์ของบรรทัดคำสั่ง คุณระบุและเนื่องจากมัน "โดดเดี่ยว" เชลล์จะพยายามเรียกมันแบบคำต่อคำ และคุณสามารถระบุชื่อฟังก์ชันเป็นอาร์กิวเมนต์แรกได้ที่นี่ ตัวอย่าง:

$ 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

สำหรับการขัดคุณสามารถตรวจสอบได้ก่อนว่าคำสั่งนั้นมีอยู่และเป็นฟังก์ชัน:

# 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
ใช้"$@"ในกรณีส่วนใหญ่ $@ไม่ปลอดภัยในบางกรณี
fumiyas

1
จะเรียกใช้มากกว่าฟังก์ชันได้อย่างไร? ตัวอย่างเช่นฉันสามารถเรียกใช้bash test.sh testA testB?
Jeff Pang

นอกจากนี้ยังต้องมีการห่อหุ้มด้วย[ ! -z "$1" ]แหล่งที่มาอื่น ๆ อีกด้วยจะทำให้เกิดคำสั่งอื่นในรูปแบบ bash
JackLeo

ฉันค้นหาตัวแปร "$ @" อันน่าอัศจรรย์นี้ทั้งใกล้และไกลเพื่อใช้ฟังก์ชันใดก็ตามที่เรียกในไฟล์ขอขอบคุณ @sdaau!
Justin Hammond

36

คำสั่งต่อไปนี้จะลงทะเบียนฟังก์ชันในบริบทก่อนจากนั้นจึงเรียกมันว่า:

. ./myScript.sh && function_name

1
คุณยังสามารถใช้แหล่งที่มา เช่นเดียวกับที่มา myScript.sh && function_name
ขโมย_leaves

17

สั้น ๆ ไม่

คุณสามารถนำเข้าฟังก์ชันทั้งหมดในสคริปต์ไปยังสภาพแวดล้อมของคุณด้วยsource( help sourceสำหรับรายละเอียด) ซึ่งจะช่วยให้คุณสามารถเรียกใช้ฟังก์ชันเหล่านั้นได้ นอกจากนี้ยังมีผลในการเรียกใช้สคริปต์ดังนั้นโปรดระวัง

ไม่มีวิธีเรียกใช้ฟังก์ชันจากเชลล์สคริปต์ราวกับว่าเป็นไลบรารีที่ใช้ร่วมกัน


1
ฉันคิดว่าควรให้น้ำหนักมากกว่านี้เพื่อเป็นคำตอบที่เหมาะสม ฉันพยายามทำสิ่งที่คล้ายกับสิ่งที่ OP ต้องการ แต่เชลล์สคริปต์ไม่ได้ออกแบบมาสำหรับ "การพัฒนา OOP ที่สะอาดหมดจด" (IMHO)
Dan L

4

การใช้ 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

สคริปต์นี้จะเรียกใช้ฟังก์ชัน fun1 และ fun2 แต่ถ้าคุณเริ่มต้นด้วยตัวเลือก fun1 หรือ fun2 มันจะเรียกใช้ฟังก์ชันที่กำหนดด้วย args (หากมีให้) และออกเท่านั้น การใช้

$ ./test 
run function1
run function2

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

1

แก้ไข: คำเตือน - ดูเหมือนว่าจะใช้ไม่ได้ในทุกกรณี แต่ใช้ได้ดีกับสคริปต์สาธารณะจำนวนมาก

หากคุณมีสคริปต์ทุบตีที่เรียกว่า "control" และข้างในนั้นคุณมีฟังก์ชันที่เรียกว่า "build":

function build() { 
  ... 
}

จากนั้นคุณสามารถเรียกสิ่งนี้ได้ (จากไดเร็กทอรีที่อยู่):

./control build

หากอยู่ในโฟลเดอร์อื่นสิ่งนั้นจะทำให้:

another_folder/control build

หากไฟล์ของคุณเรียกว่า "control.sh" มันจะทำให้ฟังก์ชันเรียกได้ดังนี้:

./control.sh build

1
สิ่งนี้ใช้ไม่ได้ในเชลล์แบบโต้ตอบสำหรับฉัน แต่สิ่งนี้ได้ผล:. ./control.sh && build
saulius2

1

ฉันมีสถานการณ์ที่ฉันต้องการฟังก์ชั่นจาก bash script ซึ่งจะต้องไม่ถูกเรียกใช้งานก่อน (เช่นโดยsource) และปัญหา@$คือ myScript.sh ถูกเรียกใช้สองครั้งดูเหมือนว่า ... ดังนั้นฉันจึงเกิดความคิด เพื่อให้ฟังก์ชันออกมาพร้อมกับ sed:

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

และเพื่อเรียกใช้งานในเวลาที่ฉันต้องการฉันใส่ไว้ในไฟล์และใช้source:

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


0

คุณสามารถเรียกใช้ฟังก์ชันจากอาร์กิวเมนต์บรรทัดคำสั่งดังต่อไปนี้

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

เมื่อคุณสิ้นสุดฟังก์ชันใส่ $ 1 เพื่อยอมรับอาร์กิวเมนต์ให้บอกว่าโค้ดด้านบนจะถูกบันทึกไว้ใน fun.sh เพื่อเรียกใช้ฟังก์ชัน ./fun.sh irfan & ./fun.sh config


0

แก้ไขโพสต์แล้ว แต่ฉันต้องการพูดถึงโซลูชันที่ฉันต้องการ กำหนดสคริปต์ซับเดียวทั่วไปeval_func.sh:

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

จากนั้นเรียกใช้ฟังก์ชันใด ๆ ภายในสคริปต์ผ่าน:

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

ปัญหาที่ฉันพบกับโซลูชันที่ยอมรับคือเมื่อจัดหาสคริปต์ที่มีฟังก์ชันของฉันภายในสคริปต์อื่นอาร์กิวเมนต์หลังจะได้รับการประเมินโดยอดีตทำให้เกิดข้อผิดพลาด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.