Làm thế nào để gọi một kịch bản shell từ một kịch bản shell khác?


739

Tôi có hai kịch bản shell, a.shb.sh.

Làm thế nào tôi có thể gọi b.shtừ trong tập lệnh shell a.sh?


8
Bạn có thể đưa ra một số chi tiết cụ thể: hệ điều hành nào và hệ vỏ nào hoặc bạn chỉ đang nói về vấn đề đó về nguyên tắc ?? Mã ví dụ cũng sẽ hữu ích.
jsalonen

14
Đây không thực sự là một câu hỏi cụ thể và cũng không thể hiện nỗ lực trước đó để giải quyết vấn đề.
Kris

1
Một vấn đề tôi gặp phải là b.shkhông có quyền thực thi. Nó có thể là một điều tốt để kiểm tra.
seth10

Nối ./trước tên kịch bản, ví dụ, thay vì: b.sh, sử dụng:./b.sh
Benny

1
Nếu bất cứ ai tiếp tục gặp No such file or directorylỗi stackoverflow.com/a/2920431/1356559
Amr Lotfy

Câu trả lời:


959

Có một vài cách khác nhau bạn có thể làm điều này:

  1. Làm cho tập lệnh khác có thể thực thi được, thêm #!/bin/bashdòng ở trên cùng và đường dẫn của tệp tới biến môi trường $ PATH. Sau đó, bạn có thể gọi nó như một lệnh bình thường;

  2. Hoặc gọi nó bằng sourcelệnh (bí danh là .) như thế này : source /path/to/script;

  3. Hoặc sử dụng bashlệnh để thực thi nó : /bin/bash /path/to/script;

Các phương thức thứ nhất và thứ ba thực thi tập lệnh như một quá trình khác, vì vậy các biến và hàm trong tập lệnh khác sẽ không thể truy cập được.
Phương thức thứ hai thực thi tập lệnh trong quy trình của tập lệnh đầu tiên và lấy các biến và hàm từ tập lệnh khác để chúng có thể sử dụng được từ tập lệnh gọi.

Trong phương thức thứ hai, nếu bạn đang sử dụng exittrong tập lệnh thứ hai, nó cũng sẽ thoát khỏi tập lệnh đầu tiên. Điều này sẽ không xảy ra trong phương pháp thứ nhất và thứ ba.


30
nhớ chmod a+x /path/to/filenếu không nó sẽ không được thực thi. Chỉ áp dụng cho phương thức ./script.
Nathan Lilienthal

3
Hãy nhớ thay đổi định dạng / mã hóa của các tệp thực thi trong unix nếu chúng được tạo trong DOS và sau đó được tải lên môi trường unix -> dos2unix <tên tập lệnh>
Abhishek Chatterjee

3
@cecillac Cách thứ nhất và thứ ba có thể là "không đồng bộ" bằng cách sử dụng cú pháp chạy nền thông thường.
Một số lập trình viên anh chàng

16
Vấn đề với sourcelà một exittuyên bố trong tập lệnh được gọi cũng sẽ thoát khỏi bạn ...
Ohad Schneider

18
@ user528025 .không phải là bí danh source, mà là cách khác. sourcelà một phần mở rộng bash, trong khi .hoạt động trong bất kỳ shell tương thích POSIX nào.
Điểm_Under

207

Kiểm tra này.

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

4
Điều này giả định rằng script.sh nằm trong cùng thư mục với bất kỳ tập lệnh nào đang chạy. Nếu bạn muốn gọi một kịch bản ở một nơi khác, bạn sẽ nóish <path to script>/script.sh
Morgan Kenyon

32
Điều này cũng sử dụng hai vỏ, bashsh. Ngay cả khi shthực tế bashnó không hoạt động giống nhau. Nếu bạn đang sử dụng #!/bin/bashthì có lẽ bạn muốn sử dụng bash script.sh(hoặc chỉ ./script.shđể sử dụng hashbang của tập lệnh đó).
Martin Tournoij

1
Giữ quyền bị từ chối ngay cả khi tôi đặt chmod +xtệp .sh. Bất kỳ đề xuất?
choàng isaac

@isaacweathers thử chmod 777
Janac Meena

114

Có một vài cách bạn có thể làm điều này. Terminal để thực thi tập lệnh:

#!/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")

Tất cả điều này là chính xác cho con đường với không gian !!!


41
Sự khác biệt của họ là gì? Tại sao một, tại sao khác?
rocketspacer

. "$ SCRIPT_PATH" được ưu tiên
Harry Mumford-Turner

1
Tôi chỉ có thể thêm rằng những thứ này không hoàn toàn tương đương, ví dụ: sh "$ SCRIPT_PATH" và bash "$ SCRIPT_PATH" sẽ không chạy tập lệnh #! / Usr / bin / mong đợi, trong khi đó chỉ là "$ SCRIPT_PATH".
Tahlor

58

Câu trả lời mà tôi đang tìm kiếm:

( exec "path/to/script" )

Như đã đề cập, execthay thế vỏ mà không tạo ra một quy trình mới. Tuy nhiên , chúng ta có thể đặt nó trong một khung con, được thực hiện bằng cách sử dụng các phép so sánh.

EDIT: Thực sự ( "path/to/script" )là đủ.


11
Điều này có vẻ khá phức tạp. Tại sao không chỉ gọi nó với /path/to/script? Tôi không thấy sự cần thiết execở đây?
Martin Tournoij

Subshell không cần thiết vì bạn không execing.
Karel Vlk

6
Làm thế nào bạn sẽ thực hiện kịch bản này với các đối số?
Bhargav

Nếu bạn vẫn muốn nắm bắt đầu ra của tập lệnh con, hãy thử $ (nguồn "đường dẫn / đến / tập lệnh")
cmcginty

@Bhargav theo liên kết này stackoverflow.com/questions/14302389/ cấp
tpbafk

16

Phụ thuộc. Tóm lại ... Nếu bạn muốn tải các biến trên bảng điều khiển hiện tại và thực thi, bạn có thể sử dụng source myshellfile.shmã của mình. Thí dụ:

!#/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

Nếu bạn chỉ muốn thực thi một tệp và điều duy nhất xen kẽ với bạn là kết quả, bạn có thể làm:

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

Tôi hy vọng sẽ giúp bạn. Cảm ơn.


2
Lưu ý rằng đó sourcelà một tính năng cụ thể bash. Vỏ bourne tiêu chuẩn chỉ có .(ví dụ . other_script.sh).
Martin Tournoij

15

Bạn có thể sử dụng /bin/shđể gọi hoặc thực thi một tập lệnh khác (thông qua tập lệnh thực tế của bạn):

 # 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

Đầu ra sẽ là:

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

1
Chắc chắn điều này sẽ chạy showdate.shdưới / bin / sh chứ không phải / bin / bash?
Chris Watts

tôi đã thử với " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" và chạy tệp: mainscript.sh và có cùng một đầu ra.
Ranjithkumar T

10

Chỉ cần thêm vào một dòng bất cứ điều gì bạn đã gõ vào một thiết bị đầu cuối để thực thi tập lệnh!
ví dụ:

#!bin/bash
./myscript.sh &

nếu tập lệnh được thực thi không nằm trong cùng thư mục, chỉ cần sử dụng đường dẫn đầy đủ của tập lệnh.
ví dụ: `/ home / user / script-thư mục /./ myscript.sh &


@Carpetsmoker &cho nhiệm vụ nền
Andrei Krasnutski

9

Trước tiên, bạn phải bao gồm các tập tin bạn gọi:

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

sau đó bạn gọi hàm của bạn như thế này:

#!/bin/bash
my_called_function

9

Nguồn đơn giản sẽ giúp bạn. Ví dụ

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

9

Nếu bạn có một tệp khác trong cùng thư mục, bạn có thể thực hiện:

bash another_script.sh

hoặc là

source another_script.sh

hoặc là

. another_script.sh

Khi bạn sử dụng bashthay vì source, tập lệnh không thể thay đổi môi trường của tập lệnh mẹ. Các .lệnh là tiêu chuẩn POSIX trong khi sourcelệnh là một bash từ đồng nghĩa dễ đọc hơn cho .(tôi thích sourcehơn .). Nếu tập lệnh của bạn nằm ở nơi khác, chỉ cần cung cấp đường dẫn đến tập lệnh đó. Cả tương đối cũng như đường dẫn đầy đủ nên làm việc.


5

Câu trả lời trên gợi ý thêm #!/bin/bashdòng vào dòng đầu tiên của tập lệnh con được gọi. Nhưng ngay cả khi bạn thêm shebang, nó sẽ nhanh hơn nhiều * để chạy tập lệnh trong trình bao phụ và thu được kết quả đầu ra:

$(source SCRIPT_NAME)

Điều này hoạt động khi bạn muốn tiếp tục chạy cùng một trình thông dịch (ví dụ: từ bash sang tập lệnh bash khác) và đảm bảo rằng dòng shebang của tập lệnh phụ không được thực thi.

Ví dụ:

#!/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

Đầu ra:

~ ❯❯❯ 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

* Ví dụ: khi virus hoặc các công cụ bảo mật đang chạy trên thiết bị, có thể mất thêm 100ms để thực hiện quy trình mới.



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
không chính xác cho scriptPathtên thư mục hoặc tệp scriptNamecó dấu cách
Andrei Krasnutski

3

Giả sử tệp mới là "/ home / satya / app / app_specific_env" và nội dung tệp như sau

#!bin/bash

export FAV_NUMBER="2211"

Nối tệp tham chiếu tệp này vào tệp ~ / .bashrc

source /home/satya/app/app_specific_env

Khi bạn khởi động lại máy hoặc đăng nhập lại, hãy thử echo $FAV_NUMBERtrong thiết bị đầu cuối. Nó sẽ xuất giá trị.

Chỉ trong trường hợp nếu bạn muốn thấy hiệu ứng ngay lập tức, source ~/.bashrctrong dòng lệnh.


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

Đó là điều duy nhất tôi cần. Khi tập lệnh được thực thi được thực thi như thế này, bạn (ít nhất là trong trường hợp của tôi) không cần bất kỳ thao tác bổ sung nào khác như shhoặc ./trong khi bạn đang gọi tập lệnh.

Cảm ơn bình luận của @Nathan Lilienthal


1

Có một số vấn đề để nhập chức năng từ tập tin khác.
Đầu tiên : Bạn không cần phải thực hiện tệp này. Tốt hơn đừng làm như vậy! chỉ cần thêm

. file

để nhập tất cả các chức năng. Và tất cả chúng sẽ như thể chúng được định nghĩa trong tệp của bạn.
Thứ hai : Bạn có thể được định nghĩa hàm có cùng tên. Nó sẽ được ghi đè. Thật tệ. Bạn có thể tuyên bố như thế

declare -f new_function_name=old_function_name 

và chỉ sau đó làm nhập khẩu. Vì vậy, bạn có thể gọi chức năng cũ bằng tên mới.
Thứ ba : Bạn chỉ có thể nhập danh sách đầy đủ các chức năng được xác định trong tệp. Nếu một số không cần thiết bạn có thể bỏ đặt chúng. Nhưng nếu bạn viết lại các chức năng của mình sau khi bỏ đặt chúng sẽ bị mất. Nhưng nếu bạn đặt tham chiếu đến nó như được mô tả ở trên, bạn có thể khôi phục sau khi hủy đặt cùng tên.
Cuối cùngTrong thủ tục nhập khẩu phổ biến là nguy hiểm và không đơn giản. Hãy cẩn thận! Bạn có thể viết kịch bản để làm điều này dễ dàng hơn và an toàn. Nếu bạn chỉ sử dụng một phần của các chức năng (không phải tất cả) thì tốt hơn nên chia chúng trong các tệp khác nhau. Thật không may, kỹ thuật này không được thực hiện tốt trong bash. Ví dụ, trong python và một số ngôn ngữ script khác, nó dễ dàng và an toàn. Có thể thực hiện nhập một phần chỉ các chức năng cần thiết với tên riêng của mình. Tất cả chúng ta đều muốn rằng trong các phiên bản bush tiếp theo sẽ được thực hiện cùng chức năng. Nhưng bây giờ chúng tôi phải viết thêm nhiều cod để làm những gì bạn muốn.


(Chào mừng bạn đến với SO!) Khi người dùng Praveen được nhìn thấy lần cuối vào năm 2011, chắc chắn rất khó để phân loại xem câu hỏi có làm thế nào để thực thi shell a.sh thực thi b.sh (và tiếp tục thực hiện a.sh nếu không ra lệnh khác ), hoặc gọi b.sh theo nghĩa đen . (Trình kiểm tra chính tả của tôi không bắt được bush versions.) (Bạn có ai đó để giúp bạn học ngữ pháp tiếng Anh không? (Đôi khi tôi ước mình có.))
greybeard

0

Sử dụng backticks.

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

Sau đó lấy đầu ra của tập lệnh sản xuất làm đối số trên tập lệnh của người tiêu dùng.

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.