Làm thế nào để lặp lại các lệnh shell khi chúng được thực thi


912

Trong tập lệnh shell, làm thế nào để tôi lặp lại tất cả các lệnh shell được gọi và mở rộng bất kỳ tên biến nào?

Ví dụ, đưa ra dòng sau:

ls $DIRNAME

Tôi muốn tập lệnh chạy lệnh và hiển thị như sau

ls /full/path/to/some/dir

Mục đích là để lưu một bản ghi của tất cả các lệnh shell được gọi và các đối số của chúng. Có lẽ có một cách tốt hơn để tạo ra một bản ghi như vậy?

Câu trả lời:


1043

set -xhoặc set -o xtracemở rộng các biến và in một dấu + nhỏ trước dòng.

set -vhoặc set -o verbosekhông mở rộng các biến trước khi in.

Sử dụng set +xset +vđể tắt các cài đặt ở trên.

Trên dòng đầu tiên của tập lệnh, người ta có thể đặt #!/bin/sh -x(hoặc -v) để có hiệu ứng tương tự như set -x(hoặc -v) sau trong tập lệnh.

Ở trên cũng hoạt động với /bin/sh.

Xem wiki của bash-hacker về setcác thuộc tính và về gỡ lỗi .

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$

7
Nếu bạn cũng muốn xem dòng nào được đánh số đang được thực thi, hãy xem stackoverflow.com/a/17805088/1729501
user13107

3
Nếu tôi muốn tô màu lệnh khi lặp lại để phân biệt lệnh và kết quả đầu ra thì sao?
Lewis Chan

11
Điều gì sẽ xảy ra nếu tôi muốn nó hát từng lệnh thông qua một bộ tổng hợp giọng nói giống như giọng hát khi lặp lại, để tôi có thể nghe những gì nó đang làm từ xa và cũng có thể thưởng thức âm nhạc? Có lẽ trong một giọng nói khác nhau cho đầu vào và đầu ra.
ADJenks

(ABS có lịch sử lâu dài không phản hồi khi yêu cầu họ sửa các ví dụ thực tiễn xấu, đến mức thúc đẩy các thành viên cộng đồng lâu đời tạo ra các tài nguyên cạnh tranh; hướng dẫn sử dụng bash chính thức cũng sẽ là nguồn lực tốt hơn).
Charles Duffy

317

set -x sẽ cung cấp cho bạn những gì bạn muốn.

Dưới đây là một kịch bản shell shell để chứng minh:

#!/bin/bash
set -x #echo on

ls $PWD

Điều này mở rộng tất cả các biến và in các lệnh đầy đủ trước khi đầu ra của lệnh.

Đầu ra:

+ ls /home/user/
file1.txt file2.txt

21
Sử dụng từ "dài dòng" theo cách đó không hoàn thành bất cứ điều gì. Bạn có thể làm set -o verbosehoặc set -v(chỉ "dài dòng") hoặc set -o xtracehoặc set -x(chỉ "xtrace") hoặc set -xv(cả hai) hoặc set -o xtrace -o verbose(cả hai).
Tạm dừng cho đến khi có thông báo mới.

điều này hoạt động tốt, nhưng lưu ý rằng "verbose" sẽ ghi đè $ 1
JasonS

90

Tôi sử dụng một chức năng để lặp lại và chạy lệnh:

#!/bin/bash
# Function to display commands
exe() { echo "\$ $@" ; "$@" ; }

exe echo hello world

Đầu ra nào

$ echo hello world
hello world

Đối với các lệnh lệnh phức tạp hơn, v.v., bạn có thể sử dụng eval:

#!/bin/bash
# Function to display commands
exe() { echo "\$ ${@/eval/}" ; "$@" ; }

exe eval "echo 'Hello, World!' | cut -d ' ' -f1"

Đầu ra nào

$  echo 'Hello, World!' | cut -d ' ' -f1
Hello

Không có nhiều phiếu cho câu trả lời này. Có một lý do đó là một ý tưởng tồi? Làm việc cho tôi và dường như chính xác là những gì tôi đang tìm kiếm ...
fru1tbat

1
Đây là câu trả lời tốt nhất nếu bạn không muốn mọi lệnh được in. Nó tránh ++ set +xđầu ra khi tắt, cũng như trông sạch hơn. Tuy nhiên, đối với chỉ một hoặc hai câu, câu trả lời của bhassel bằng cách sử dụng một mạng con là thuận tiện nhất.
Brent Faust

Đây là những gì tôi đang tìm kiếm! Không set +x, nó ảnh hưởng đến tất cả các lệnh, đó là quá nhiều!
Hlung

11
Một nhược điểm lớn của điều này là đầu ra mất thông tin trích dẫn. Bạn không thể phân biệt giữa cp "foo bar" bazcp foo "bar baz", ví dụ. Vì vậy, nó tốt để hiển thị thông tin tiến trình cho người dùng; ít hơn để gỡ lỗi đầu ra hoặc ghi lại các lệnh tái tạo. Các trường hợp sử dụng khác nhau. Trong zsh, bạn có thể giữ nguyên trích dẫn với công cụ :qsửa đổi:exe() { echo '$' "${@:q}" ; "$@" ; }
Andrew Janke

2
Tôi không thích câu trả lời này. Có rất nhiều trường hợp cạnh mà những gì bạn nhìn thấy không phải là những gì bạn nhận được (đặc biệt là với khoảng trắng, dấu ngoặc kép, ký tự thoát, thay thế biến / biểu thức, v.v.), vì vậy đừng dán mù lệnh bị lặp vào thiết bị đầu cuối và cho rằng nó sẽ chạy cùng một cách Ngoài ra, kỹ thuật thứ hai chỉ là một bản hack và sẽ loại bỏ các trường hợp khác của từ evalkhỏi lệnh của bạn. Vì vậy, đừng mong đợi nó hoạt động đúng exe eval "echo 'eval world'"!
mwfearnley

88

Bạn cũng có thể chuyển đổi phần này cho các dòng được chọn trong tập lệnh của mình bằng cách gói chúng vào set -xset +x, ví dụ:

#!/bin/bash
...
if [[ ! -e $OUT_FILE ]];
then
   echo "grabbing $URL"
   set -x
   curl --fail --noproxy $SERV -s -S $URL -o $OUT_FILE
   set +x
fi

54

Câu trả lời của shuckc cho việc lặp lại các dòng chọn có một vài nhược điểm: cuối cùng bạn set +xcũng bị lặp lại lệnh sau và bạn sẽ mất khả năng kiểm tra mã thoát $?vì nó bị ghi đè bởi set +x.

Một tùy chọn khác là chạy lệnh trong một khung con:

echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )

if [ $? -eq 0 ] ; then
    echo "curl failed"
    exit 1
fi

Nó sẽ cung cấp cho bạn đầu ra như:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed

Tuy nhiên, điều này không phải chịu chi phí tạo ra một lớp con mới cho lệnh.


7
Cách tốt đẹp để tránh ++ set +xđầu ra.
Brent Faust

3
Thậm chí tốt hơn: thay thế if [ $? -eq 0 ]bằng if (set -x; COMMAND).
Amedee Van Gasse

35

Một tùy chọn khác là đặt "-x" ở đầu tập lệnh của bạn thay vì trên dòng lệnh:

$ cat ./server
#!/bin/bash -x
ssh user@server

$ ./server
+ ssh user@server
user@server's password: ^C
$

Lưu ý rằng điều này dường như không hoạt động chính xác như nhau giữa ./myScriptbash myScript. Vẫn là một điều tốt để chỉ ra, cảm ơn.
altendky

27

Theo TLDP 's Bash Hướng dẫn cho người mới bắt đầu: Chương 2. Viết và các kịch bản gỡ lỗi :

2.3.1. Gỡ lỗi trên toàn bộ tập lệnh

$ bash -x script1.sh

...

Hiện tại đã có một trình gỡ lỗi chính thức cho Bash, có sẵn tại SourceForge . Các tính năng sửa lỗi này có sẵn trong hầu hết các phiên bản hiện đại của Bash, bắt đầu từ 3.x.

2.3.2. Gỡ lỗi một phần của tập lệnh

set -x            # Activate debugging from here
w
set +x            # Stop debugging from here

...

Bảng 2-1. Tổng quan về các tùy chọn gỡ lỗi thiết lập

    Short  | Long notation | Result
    -------+---------------+--------------------------------------------------------------
    set -f | set -o noglob | Disable file name generation using metacharacters (globbing).
    set -v | set -o verbose| Prints shell input lines as they are read.
    set -x | set -o xtrace | Print command traces before executing command.

...

Ngoài ra, các chế độ này có thể được chỉ định trong chính tập lệnh, bằng cách thêm các tùy chọn mong muốn vào khai báo shell dòng đầu tiên. Các tùy chọn có thể được kết hợp, như thường thấy với các lệnh UNIX:

#!/bin/bash -xv

18

Nhập "bash -x" trên dòng lệnh trước tên của tập lệnh Bash. Ví dụ, để thực thi foo.sh, gõ:

bash -x foo.sh

11

Bạn có thể thực thi một tập lệnh Bash trong chế độ gỡ lỗi với -xtùy chọn .

Điều này sẽ lặp lại tất cả các lệnh.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

Bạn cũng có thể lưu tùy chọn -x trong tập lệnh . Chỉ cần xác định -xtùy chọn trong shebang.

######## example_script.sh ###################
#!/bin/bash -x

cd /home/user
mv text.txt mytext.txt

##############################################

./example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

2
Cũng bash -vxsẽ làm tương tự nhưng không có nội suy thay đổi
loa_in_

4

Đối với zsh, echo

 setopt VERBOSE

Và để gỡ lỗi,

 setopt XTRACE

2

Đối với cshtcsh, bạn có thể set verbosehoặc set echo(hoặc thậm chí bạn có thể đặt cả hai, nhưng nó có thể dẫn đến một số trùng lặp hầu hết thời gian).

Các verbosetùy chọn in khá nhiều biểu hiện vỏ chính xác mà bạn gõ.

Các echotùy chọn chỉ mang nhiều hơn những gì sẽ được thực hiện thông qua sinh sản.


http://www.tcsh.org/tcsh.html/ecial_shell_variables.html#verbose

http://www.tcsh.org/tcsh.html/ecial_shell_variables.html#echo


Special shell variables

verbose If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.

echo If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.


1
$ cat exampleScript.sh
#!/bin/bash
name="karthik";
echo $name;

bash -x exampleScript.sh

Đầu ra như sau:

nhập mô tả hình ảnh ở đây


Các định nghĩa màu cho thiết bị đầu cuối của bạn (RGB, số) là gì?
Peter Mortensen

1

Để cho phép các lệnh ghép được lặp lại, tôi sử dụng hàm evalcộng của Soth exeđể lặp lại và chạy lệnh. Điều này hữu ích cho các lệnh đường ống mà nếu không chỉ hiển thị hoặc không chỉ phần ban đầu của lệnh đường ống.

Không có eval:

exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt

Đầu ra:

$
file.txt

Với eval:

exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'

Đầu ra nào

$ exe eval 'ls -F | grep *.txt'
file.txt
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.