Các cách khác nhau để thực thi tập lệnh shell


44

Có một số cách để thực thi một tập lệnh, những cách tôi biết là:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

Là nhiều hơn về điều này? Sự khác biệt giữa chúng là gì? Có những tình huống mà tôi phải sử dụng cái này chứ không phải cái khác?


Thật tuyệt khi biết, nhờ câu hỏi và câu trả lời của bạn dưới đây, đặc biệt là của Shawn. Tôi muốn thêm một cái gì đó không rõ ràng cho tôi cho đến khi tôi chạy một vài thử nghiệm. Bao gồm một "/" theo cách thứ hai ở trên sẽ đưa lệnh đến chế độ 1 ở trên. Đó là, trong khi "./myscript.sh" theo chế độ 1, ". Myscript.sh" dính vào chế độ 2. Bạn đã đề cập đến "sử dụng đường dẫn (tuyệt đối hoặc tương đối)", nhưng chỉ muốn làm rõ điều này.
Arun

Câu trả lời:


32

Một cách khác là gọi trình thông dịch và chuyển đường dẫn tới tập lệnh tới nó:

/bin/sh /path/to/script

Dấu chấm và nguồn tương đương. (EDIT: không, chúng không phải: như KeithB đã chỉ ra trong một nhận xét về câu trả lời khác, "." Chỉ hoạt động trong các shell liên quan đến bash, trong đó "nguồn" hoạt động trong cả shell bash và csh.) Nó thực thi đoạn script trong -place (như thể bạn đã sao chép và dán tập lệnh ngay tại đó). Điều này có nghĩa là bất kỳ hàm và biến không cục bộ nào trong tập lệnh vẫn còn. Điều đó cũng có nghĩa là nếu tập lệnh thực hiện một cd vào một thư mục, bạn sẽ vẫn ở đó khi hoàn thành.

Các cách khác để chạy một kịch bản sẽ chạy nó trong lớp con riêng của nó. Các biến trong kịch bản không còn tồn tại khi hoàn thành. Nếu tập lệnh thay đổi thư mục, thì nó không ảnh hưởng đến môi trường gọi.

/ path / to / script và / bin / sh script hơi khác nhau. Thông thường, một kịch bản có "shebang" ở đầu giống như thế này:

#! /bin/bash

Đây là đường dẫn đến trình thông dịch kịch bản. Nếu nó chỉ định một trình thông dịch khác với bạn khi bạn thực thi nó, thì nó có thể hoạt động khác đi (hoặc có thể không hoạt động gì cả).

Ví dụ: tập lệnh Perl và tập lệnh Ruby bắt đầu bằng (tương ứng):

#! /bin/perl

#! /bin/ruby

Nếu bạn thực thi một trong những tập lệnh đó bằng cách chạy /bin/sh script, thì chúng sẽ không hoạt động.

Ubuntu thực sự không sử dụng bash shell, nhưng một cái rất giống được gọi là dash. Các tập lệnh yêu cầu bash có thể hoạt động hơi sai khi được gọi bằng cách thực hiện /bin/sh scriptvì bạn vừa gọi một tập lệnh bash bằng trình thông dịch dấu gạch ngang.

Một điểm khác biệt nhỏ giữa gọi trực tiếp tập lệnh và chuyển đường dẫn kịch bản tới trình thông dịch là tập lệnh phải được đánh dấu thực thi để chạy trực tiếp, nhưng không được chạy bằng cách chuyển đường dẫn đến trình thông dịch.

Một biến thể nhỏ khác: bạn có thể thêm tiền tố vào bất kỳ cách nào trong số những cách này để thực thi tập lệnh với eval, vì vậy, bạn có thể có

eval sh script
eval script
eval . script

vân vân Nó không thực sự thay đổi bất cứ điều gì, nhưng tôi nghĩ tôi nên bao gồm nó cho triệt để.


6
Nói "Ubuntu thực sự không sử dụng bash shell" là không chính xác và về mặt kỹ thuật không chính xác. Ubuntu không sử dụng bash shell, điểm shtương ứng dash, nhưng không phải bash.
Faheem Mitha

@Shawn Trong fumps para bạn đã viết "Nó thực thi tập lệnh tại chỗ (như thể bạn đã sao chép và dán tập lệnh ngay tại đó). Điều này có nghĩa là vẫn còn bất kỳ chức năng và biến không cục bộ nào trong tập lệnh." bạn có ý nghĩa gì bởi dòng thứ hai ở đây? Bạn có thể giải thích dùm không.
Geek

@Geek khi bạn thực thi một tập lệnh như một tiến trình con (cách thông thường), mọi biến và chức năng mà nó xác định (môi trường của nó) sẽ biến mất khi quá trình kết thúc. Nếu bạn lấy tập lệnh, các biến và hàm đó được tạo trong môi trường hiện tại; khi kịch bản kết thúc, các thay đổi đối với môi trường vẫn còn.
Shawn J. Goff

@ ShawnJ.Goff cảm ơn đã làm rõ. +1.
Geek

Plot-twist: Bourne Shell (sh) chỉ chấp nhận dấu chấm - không phải nguồn vì nó là bash-dựng sẵn. pubs.opengroup.org/onlinepub/9699919799/utilities/NH Vì vậy, tôi muốn nói cách di động nhất là dấu chấm.
dezza

9

Hầu hết mọi người gỡ lỗi các tập lệnh shell bằng cách thêm các cờ gỡ lỗi sau vào tập lệnh:

set -x     # Print command traces before executing command.
set -v     # Prints shell input lines as they are read.
set -xv    # Or do both

Nhưng điều này có nghĩa là bạn cần mở tệp bằng trình chỉnh sửa (giả sử bạn có quyền chỉnh sửa tệp), thêm một dòng như set -x, lưu tệp, sau đó thực hiện tệp. Sau đó, khi bạn đã hoàn tất, bạn cần làm theo các bước tương tự và loại bỏ set -x, v.v ... Điều này có thể tẻ nhạt.

Thay vì làm tất cả những điều đó, bạn có thể đặt cờ gỡ lỗi trên dòng lệnh:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...

2
Một mẹo có liên quan: Tôi đã có thói quen đặt emulate sh 2>/dev/nulllên hàng đầu các tập lệnh shell của mình. Khi chạy với zsh, điều này đặt nó vào chế độ tương thích POSIX. Khi chạy với các shell khác, dòng không có hiệu lực. Sau đó tôi có thể chạy tập lệnh với zsh -x /path/to/script. Tôi thích zsh ở đây vì nó cung cấp dấu vết tốt hơn bash hoặc ksh.
Gilles 'SO- ngừng trở nên xấu xa'

7

Shawn J. Goff đã đưa ra rất nhiều điểm hay, nhưng không bao gồm toàn bộ câu chuyện:

Ubuntu thực sự không sử dụng bash shell, nhưng một cái rất giống được gọi là dash. Các tập lệnh yêu cầu bash có thể hoạt động hơi sai khi được gọi bằng cách thực hiện /bin/shtập lệnh vì bạn vừa gọi tập lệnh bash bằng trình thông dịch dấu gạch ngang.

Rất nhiều tập lệnh hệ thống (như trong init.d, in / etc, v.v.) có một shebang #!/bin/sh, nhưng /bin/shthực tế là một liên kết tượng trưng đến một trình bao khác - /bin/bashngày nay, ngày nay /bin/dash. Nhưng khi một trong số chúng được gọi là /bin/sh, chúng hoạt động khác đi, tức là chúng dính vào chế độ tương thích POSIX.

Làm thế nào để họ làm điều này? Vâng, họ kiểm tra làm thế nào họ được viện dẫn.

Một shellscript có thể kiểm tra làm thế nào nó được gọi, và làm những việc khác nhau, tùy thuộc vào điều đó? Vâng, nó có thể. Vì vậy, cách bạn gọi nó luôn có thể dẫn đến các kết quả khác nhau, nhưng tất nhiên nó hiếm khi được thực hiện để làm phiền bạn. :)

Như một quy tắc tự nhiên: Nếu bạn đang học một shell cụ thể như bash và viết các lệnh từ một hướng dẫn bash, hãy đặt #!/bin/bashtiêu đề, không #!/bin/sh, trừ khi có ghi chú khác. Khác lệnh của bạn có thể thất bại. Và nếu bạn không tự viết một tập lệnh, hãy gọi nó trực tiếp ( ./foo.sh, bar/foo.sh) thay vì đoán shell ( sh foo.sh, sh bar/foo.sh). Các shebang nên gọi vỏ phải.

Và đây là hai loại gọi khác:

cat foo.sh | dash
dash < foo.sh

5

.sourcetương đương ở chỗ chúng không sinh ra một quy trình con mà thực thi các lệnh trong trình bao hiện tại. Điều này rất quan trọng khi tập lệnh đặt các biến môi trường hoặc thay đổi thư mục làm việc hiện tại.

Sử dụng đường dẫn hoặc cho nó để /bin/shtạo ra một quy trình mới trong đó các lệnh được thực thi.


2
sh script
bash script

Tôi đang cân nhắc nếu có nhiều ...

.sourcegiống nhau Sau khi thực hiện, mọi thay đổi của môi trường scriptsẽ được giữ lại. Thông thường, nó sẽ được sử dụng để lấy nguồn thư viện Bash, vì vậy thư viện có thể được sử dụng lại trong nhiều tập lệnh khác nhau.

Ngoài ra đó là một cách tốt để giữ thư mục hiện tại. Nếu bạn thay đổi thư mục trong tập lệnh, nó sẽ không được áp dụng trong trình bao mà bạn thực thi tập lệnh đó. Nhưng nếu bạn lấy nó để chạy nó, sau khi đoạn script thoát ra, thư mục hiện tại sẽ được giữ lại.


2
.chỉ hoạt động trong sh / bash và shell liên quan. sourcecũng hoạt động trong csh và vỏ liên quan.
KeithB

1

Liệu " userland exec " có được tính như một cách khác không? Userland exec tải mã và để nó thực thi mà không cần sử dụng lệnh gọi hệ thống execve ().


1
. ./filename
# ( dot space dot slash filename )

Chạy script trong shell hiện tại khi thư mục không nằm trong đường dẫn.


1

. và nguồn ít nhất một chút trong zsh (đó là những gì tôi sử dụng) bởi vì

source file

Hoạt động, trong khi

. file

không, nó cần

. ./file
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.