วิธีเรียกเชลล์สคริปต์หนึ่งจากเชลล์สคริปต์อื่น


739

ฉันมีเชลล์สคริปต์สองตัวa.shและb.sh.

ฉันจะโทรb.shจากภายในสคริปต์เชลล์ได้a.shอย่างไร


8
คุณสามารถให้รายละเอียดบางอย่าง: ระบบปฏิบัติการใดและเชลล์ใดหรือคุณเพิ่งพูดถึงปัญหานั้นในหลักการ? โค้ดตัวอย่างจะมีประโยชน์เช่นกัน
jsalonen

14
นี่ไม่ใช่คำถามที่เฉพาะเจาะจงหรือไม่แสดงให้เห็นถึงความพยายามก่อนหน้าในการแก้ไขปัญหา
กริช

1
ปัญหาหนึ่งที่ฉันมีคือb.shไม่มีสิทธิ์ในการใช้งานได้ มันอาจเป็นสิ่งที่ดีในการตรวจสอบ
seth10

ต่อท้าย./ชื่อสคริปต์ตัวอย่างเช่น: b.sh, use:./b.sh
Benny

1
หากใครยังคงได้รับNo such file or directoryข้อผิดพลาดstackoverflow.com/a/2920431/1356559
Amr Lotfy

คำตอบ:


959

มีหลายวิธีที่คุณสามารถทำได้:

  1. ทำให้สคริปต์อื่นสามารถทำงานได้เพิ่ม#!/bin/bashบรรทัดที่ด้านบนและพา ธ ที่ไฟล์นั้นอยู่ในตัวแปรสภาพแวดล้อม $ PATH จากนั้นคุณสามารถเรียกมันว่าเป็นคำสั่งปกติ

  2. หรือเรียกมันด้วยsourceคำสั่ง (นามแฝง.) เช่นนี้: source /path/to/script;

  3. หรือใช้bashคำสั่งเพื่อรันมัน: /bin/bash /path/to/script;

วิธีที่หนึ่งและสามเรียกใช้สคริปต์เป็นกระบวนการอื่นดังนั้นตัวแปรและฟังก์ชันในสคริปต์อื่นจะไม่สามารถเข้าถึงได้
วิธีที่สองเรียกใช้งานสคริปต์ในกระบวนการของสคริปต์แรกและดึงตัวแปรและฟังก์ชั่นจากสคริปต์อื่นเพื่อให้สามารถใช้งานได้จากสคริปต์การโทร

ในวิธีที่สองหากคุณใช้exitในสคริปต์ที่สองมันจะออกจากสคริปต์แรกเช่นกัน ซึ่งจะไม่เกิดขึ้นในวิธีแรกและวิธีที่สาม


30
จำไว้chmod a+x /path/to/fileมิฉะนั้นจะไม่สามารถเรียกใช้งานได้ ใช้กับวิธีการ. / สคริปต์เท่านั้น
Nathan Lilienthal

3
จำไว้ว่าให้เปลี่ยนรูปแบบ / การเข้ารหัสไฟล์ที่ปฏิบัติการได้ในยูนิกซ์หากไฟล์เหล่านั้นถูกสร้างขึ้นใน DOS แล้วอัปโหลดไปยังระบบปฏิบัติการยูนิกซ์ -> dos2unix <ชื่อสคริปต์>
Abhishek Chatterjee

3
@cecemel วิธีที่หนึ่งและสามอาจเป็น "async" โดยใช้ไวยากรณ์การเรียกใช้แบบพื้นหลังปกติ
โปรแกรมเมอร์บางคนเพื่อน

16
ปัญหากับการsourceเป็นว่าexitคำสั่งในสคริปต์ที่เรียกว่าจะออกจากคุณเช่นกัน ...
Ohad Schneider

18
@ user528025 .ไม่ใช่นามแฝงsourceแต่เป็นวิธีอื่น sourceเป็นส่วนขยายทุบตีในขณะที่.ทำงานในเชลล์ที่รองรับ POSIX
คะแนน _ ต่ำกว่า

207

ลองดู.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."

4
สิ่งนี้จะถือว่า script.sh อยู่ในไดเรกทอรีเดียวกับสิ่งที่สคริปต์กำลังทำงานอยู่ หากคุณต้องการเรียกใช้สคริปต์จากที่อื่นคุณอาจพูดว่าsh <path to script>/script.sh
Morgan Kenyon

32
นอกจากนี้ยังใช้สองเปลือกหอยและbash shแม้ว่าshในความเป็นจริงbashมันจะไม่ทำงานเหมือนกัน หากคุณกำลังใช้งานอยู่#!/bin/bashคุณอาจต้องการใช้bash script.sh(หรือเพียงแค่./script.shใช้ hashbang ของสคริปต์นั้น)
Martin Tournoij

1
ผู้ดูแลได้รับสิทธิ์ปฏิเสธข้อผิดพลาดแม้ว่าฉันจะตั้งค่าเป็นchmod +xไฟล์. ข้อเสนอแนะใด ๆ
isaac weathers

@isaacweathers ลอง chmod 777
Janac Meena

114

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

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

ทั้งหมดนี้ถูกต้องสำหรับเส้นทางที่มีช่องว่าง !!!


41
ความแตกต่างของพวกเขาคืออะไร? ทำไมคนหนึ่งทำไมคนอื่น?
rocketspacer

. แนะนำให้ใช้ "$ SCRIPT_PATH"
Harry Mumford-Turner

1
ฉันสามารถเพิ่มได้ว่าสิ่งเหล่านี้จะไม่เทียบเท่าทั้งหมดเช่น sh "$ SCRIPT_PATH" และทุบตี "$ SCRIPT_PATH" จะไม่ทำงาน #! / usr / bin / สคริปต์ที่คาดหวังในขณะที่เพียงแค่ "$ SCRIPT_PATH" จะ
Tahlor

58

คำตอบที่ฉันกำลังมองหา:

( exec "path/to/script" )

ดังที่กล่าวexecมาแทนที่เชลล์โดยไม่ต้องสร้างกระบวนการใหม่ อย่างไรก็ตามเราสามารถใส่มันลงใน subshell ซึ่งทำได้โดยใช้ parantheses

แก้ไข: จริง ๆ แล้ว( "path/to/script" )ก็เพียงพอแล้ว


11
ดูเหมือนว่าจะค่อนข้างซับซ้อน ทำไมไม่เรียกมันด้วย/path/to/script? ฉันไม่เห็นความต้องการexecที่นี่เลยเหรอ?
Martin Tournoij

ไม่จำเป็นต้องใช้ subshell ตั้งแต่คุณไม่ได้เข้าexecชม
Karel Vlk

6
คุณจะเรียกใช้สคริปต์นี้ด้วยอาร์กิวเมนต์อย่างไร
Bhargav

หากคุณยังต้องการจับเอาท์พุทของสคริปต์ย่อยลองใช้ $ (ซอร์ส "path / to / script")
cmcginty

@Bhargav ติดตามลิงค์นี้stackoverflow.com/questions/14302389/…
tpbafk

16

ขึ้นอยู่กับ. สั้น ๆ ... หากคุณต้องการตัวแปรโหลดในคอนโซลปัจจุบันและรันคุณสามารถใช้source myshellfile.shกับรหัสของคุณ ตัวอย่าง:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

หากคุณต้องการรันไฟล์และสิ่งเดียวที่รบกวนคุณคือผลลัพธ์คุณสามารถทำสิ่งต่อไปนี้

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

ฉันหวังว่าจะช่วยคุณ ขอบคุณ


2
โปรดทราบว่าsourceนี่เป็นคุณสมบัติเฉพาะของ bash เปลือก bourne มาตรฐานมีเพียง.(เช่น. other_script.sh)
Martin Tournoij

15

คุณสามารถใช้/bin/shโทรหรือรันสคริปต์อื่น (ผ่านสคริปต์จริงของคุณ):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

ผลลัพธ์จะเป็น:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013

1
แน่นอนว่าสิ่งนี้จะทำงานshowdate.shภายใต้ / bin / sh มากกว่า / bin / bash?
Chris Watts

ฉันได้ลองกับ " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" และเรียกใช้ไฟล์: mainscript.sh และได้ผลลัพธ์เดียวกัน
Ranjithkumar T

10

เพียงเพิ่มบรรทัดอะไรก็ตามที่คุณจะพิมพ์ลงในเทอร์มินัลเพื่อรันสคริปต์!
เช่น:

#!bin/bash
./myscript.sh &

หากสคริปต์ที่จะดำเนินการไม่อยู่ในไดเรกทอรีเดียวกันให้ใช้พา ธ ที่สมบูรณ์ของสคริปต์
เช่น: `/ home / user / script-directory /./ myscript.sh &


@Carpetsmoker &สำหรับงานพื้นหลัง
Andrei Krasutski

9

ก่อนอื่นคุณต้องรวมไฟล์ที่คุณโทร:

#!/bin/bash
. includes/included_file.sh

จากนั้นคุณเรียกฟังก์ชันของคุณดังนี้:

#!/bin/bash
my_called_function

9

แหล่งที่เรียบง่ายจะช่วยคุณ สำหรับอดีต

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"

9

หากคุณมีไฟล์อื่นในไดเรกทอรีเดียวกันคุณสามารถทำได้:

bash another_script.sh

หรือ

source another_script.sh

หรือ

. another_script.sh

เมื่อคุณใช้bashแทนsourceสคริปต์จะไม่สามารถเปลี่ยนสภาพแวดล้อมของสคริปต์หลัก .คำสั่งมาตรฐาน POSIX ในขณะที่sourceคำสั่งเป็นคำพ้องทุบตีอ่านได้มากขึ้นสำหรับ.(ฉันชอบsourceมากกว่า.) หากสคริปต์ของคุณอยู่ที่อื่นให้ระบุเส้นทางไปยังสคริปต์นั้น ทั้งญาติและเส้นทางเต็มควรทำงาน


5

คำตอบยอดนิยมแนะนำให้เพิ่ม#!/bin/bashบรรทัดในบรรทัดแรกของสคริปต์ย่อยที่เรียก แต่แม้ว่าคุณจะเพิ่ม shebang มันจะเร็วยิ่งกว่า*ในการรันสคริปต์ใน sub-shell และดักจับเอาต์พุต:

$(source SCRIPT_NAME)

วิธีนี้จะทำงานเมื่อคุณต้องการใช้งานล่ามเดียวกัน (เช่นจากทุบตีไปจนถึงสคริปต์ทุบตีอื่น) และตรวจสอบให้แน่ใจว่าบรรทัด Shebang ของสคริปต์ย่อยนั้นไม่ได้ทำงาน

ตัวอย่างเช่น:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

เอาท์พุท:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

*ตัวอย่างเช่นเมื่อไวรัสหรือเครื่องมือความปลอดภัยทำงานบนอุปกรณ์อาจใช้เวลาเพิ่มอีก 100 มิลลิวินาทีในการดำเนินกระบวนการใหม่



4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?

1
ไม่ถูกต้องสำหรับโฟลเดอร์scriptPathหรือชื่อไฟล์ที่scriptNameมีช่องว่าง
Andrei Krasutski

3

สมมติว่าไฟล์ใหม่คือ "/ home / satya / app / app_specific_env" และเนื้อหาไฟล์มีดังนี้

#!bin/bash

export FAV_NUMBER="2211"

ผนวกการอ้างอิงไฟล์นี้กับไฟล์ ~ / .bashrc

source /home/satya/app/app_specific_env

เมื่อใดก็ตามที่คุณรีสตาร์ทเครื่องหรือ relogin ลองecho $FAV_NUMBERใน terminal มันจะส่งออกค่า

ในกรณีที่คุณต้องการเห็นผลทันทีsource ~/.bashrcในบรรทัดคำสั่ง


3
chmod a+x /path/to/file-to-be-executed

นั่นเป็นสิ่งเดียวที่ฉันต้องการ เมื่อสคริปต์ที่จะเรียกใช้งานนั้นสามารถเรียกใช้งานได้เช่นนี้คุณ (อย่างน้อยในกรณีของฉัน) ไม่ต้องการการดำเนินการพิเศษอื่น ๆ เช่นshหรือ./ขณะที่คุณกำลังเรียกใช้สคริปต์

ขอบคุณที่แสดงความคิดเห็นของ @Nathan Lilienthal


1

มีปัญหาในการนำเข้าฟังก์ชั่นจากไฟล์อื่น
แรก : คุณไม่จำเป็นต้องทำไฟล์นี้ปฏิบัติการ ดีกว่าที่จะไม่ทำเช่นนั้น! เพียงเพิ่ม

. file

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

declare -f new_function_name=old_function_name 

และหลังจากนั้นจะนำเข้า ดังนั้นคุณอาจเรียกฟังก์ชันเก่าด้วยชื่อใหม่
ประการที่สาม : คุณสามารถนำเข้าเฉพาะรายการฟังก์ชั่นที่กำหนดไว้ในไฟล์เท่านั้น หากบางคนไม่จำเป็นคุณอาจยกเลิกการตั้งค่าพวกเขา แต่ถ้าคุณเขียนฟังก์ชั่นใหม่หลังจากไม่ได้ตั้งค่ามันจะหายไป แต่ถ้าคุณตั้งค่าการอ้างอิงตามที่อธิบายไว้ข้างต้นคุณสามารถคืนค่าหลังจากไม่ได้ตั้งชื่อเดียวกัน
ในที่สุดในขั้นตอนทั่วไปของการนำเข้ามีอันตรายและไม่ง่าย ระวัง! คุณอาจเขียนสคริปต์เพื่อทำสิ่งนี้ให้ง่ายและปลอดภัยยิ่งขึ้น หากคุณใช้เพียงบางส่วนของฟังก์ชั่น (ไม่ใช่ทั้งหมด) แยกไฟล์เหล่านั้นออกเป็นไฟล์ต่างๆ น่าเสียดายที่เทคนิคนี้ใช้ไม่ได้กับการทุบตี ในภาษาไพ ธ อนและภาษาสคริปต์อื่น ๆ นั้นง่ายและปลอดภัย เป็นไปได้ที่จะทำให้การนำเข้าบางส่วนเพียงฟังก์ชั่นที่จำเป็นด้วยชื่อของตัวเอง เราทุกคนต้องการให้ในรุ่นต่อไปของบุชจะทำหน้าที่การทำงานเดียวกัน แต่ตอนนี้เราต้องเขียนรหัสเพิ่มเติมมากมายเพื่อทำสิ่งที่คุณต้องการ


(ยินดีต้อนรับสู่ SO!) ดังที่ผู้ใช้Praveenเห็นครั้งล่าสุดในปี 2554 มันยากที่จะแยกแยะว่าคำถามนั้นเป็นอย่างไรที่จะทำให้เชลล์ดำเนินการ a.sh รัน b.sh (และดำเนินการ a.sh ต่อไปหากไม่ดำเนินการต่อ) สั่งเป็นอย่างอื่น ) หรือโทร b.shอย่างแท้จริง (ตัวตรวจสอบการสะกดคำของฉันไม่ทันbush versions) (คุณมีคนที่หันไปช่วยไวยากรณ์ภาษาอังกฤษหรือเปล่า (บางครั้งฉันอยากได้))
greybeard

0

ใช้ backticks

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

จากนั้นดึงเอาท์พุทของสคริปต์ผู้สร้างมาเป็นอาร์กิวเมนต์ในสคริปต์ผู้บริโภค

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