it-swarm-vi.com

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

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?

44
phunehehe

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. . -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 tập lệnh 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à 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, sau đó họ sẽ không làm việc gì cả.

Ubuntu thực sự không sử dụng bash Shell, nhưng một thứ 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 script bởi vì 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 việc 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 để 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à như thế. Nó không thực sự thay đổi bất cứ điều gì, nhưng tôi nghĩ tôi nên đưa nó vào sự thấu đáo.

32
Shawn J. Goff

Hầu hết mọi người gỡ lỗi các tập lệnh Shell bằng cách thêm vào sau gỡ lỗi cờ 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 thành, bạn cần làm theo các bước tương tự và xóa 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
...
...
9
Stefan Lasiewski

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 thứ 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 tậ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ó Shebang #!/bin/sh, nhưng /bin/sh thực tế là một liên kết tượng trưng đến một Shell khác - trong thời gian trước /bin/bash, 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 nhau, 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. :)

Theo nguyên tắc thông thường: Nếu bạn đang học một Shell cụ thể như bash và viết lệnh từ hướng dẫn bash, hãy đặt #!/bin/bash trong tiêu đề, không phải #!/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 kịch bản, 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). Shebang nên gọi Shell đúng.

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

cat foo.sh | dash
dash < foo.sh
7
user unknown

.source tương đương ở chỗ chúng không sinh ra một quy trình con mà thực hiện các lệnh trong Shell 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 đưa nó cho /bin/sh tạo ra một quy trình mới trong đó các lệnh được thực thi.

5
mouviciel
sh script
bash script

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

.source giống nhau. Sau khi thực hiện mọi thay đổi của môi trường trong script sẽ đượ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 Shell 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
livibetter

. 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
1
bollovan
. ./filename
# ( dot space dot slash filename )

Chạy tập lệnh trong Shell hiện tại khi thư mục không nằm trong đường dẫn.

1
jrh_enginnering

" serland exec " có được tính là 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
Bruce Ediger