Khi bạn ngẩng cao cổ, bạn sẽ dễ dàng quên rằng mục tiêu là thoát khỏi đầm lầy.
- câu nói phổ biến
Câu hỏi là về echo
, và phần lớn các câu trả lời cho đến nay đã tập trung vào cách lén một set +x
lệnh. Có một giải pháp trực tiếp, đơn giản hơn nhiều:
{ echo "Message"; } 2> /dev/null
(Tôi thừa nhận rằng tôi có thể đã không nghĩ đến { …; } 2> /dev/null
nếu tôi không nhìn thấy nó trong các câu trả lời trước đó.)
Điều này hơi khó khăn, nhưng, nếu bạn có một khối các echo
lệnh liên tiếp , bạn không cần phải thực hiện từng lệnh một:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Lưu ý rằng bạn không cần dấu chấm phẩy khi bạn có dòng mới.
Bạn có thể giảm gánh nặng gõ bằng cách sử dụng ý tưởng
mở /dev/null
vĩnh viễn của kenorb trên một bộ mô tả tệp không chuẩn (ví dụ: 3) và sau đó nói 2>&3
thay vì 2> /dev/null
mọi lúc.
Bốn câu trả lời đầu tiên tại thời điểm viết bài này đòi hỏi phải làm một điều gì đó đặc biệt (và, trong hầu hết các trường hợp, cồng kềnh)
mỗi khi bạn làm một echo
. Nếu bạn thực sự muốn tất cả echo
các lệnh để loại bỏ dấu vết thực thi (và tại sao bạn lại không?), Bạn có thể làm như vậy trên toàn cầu mà không cần phải trộn nhiều mã. Đầu tiên, tôi nhận thấy rằng các bí danh không được theo dõi:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Lưu ý rằng đoạn mã sau hoạt động nếu shebang là #!/bin/sh
, ngay cả khi /bin/sh
là liên kết đến bash. Nhưng, nếu shebang là #!/bin/bash
, bạn cần thêm một shopt -s expand_aliases
lệnh để có bí danh hoạt động trong tập lệnh.)
Vì vậy, cho mẹo đầu tiên của tôi:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Bây giờ, khi chúng tôi nói echo "Message"
, chúng tôi đang gọi bí danh, không được truy tìm. Bí danh tắt tùy chọn theo dõi, đồng thời chặn thông báo theo dõi khỏi set
lệnh (sử dụng kỹ thuật được trình bày trước trong câu trả lời của người dùng ), sau đó thực hiện echo
lệnh thực tế . Điều này cho phép chúng tôi có được một hiệu ứng tương tự như câu trả lời của người dùng5071535 mà không cần chỉnh sửa mã ở mỗi echo
lệnh. Tuy nhiên, chế độ theo dõi lá này đã tắt. Chúng ta không thể đặt một set -x
bí danh (hoặc ít nhất là không dễ dàng) vì bí danh chỉ cho phép một chuỗi được thay thế cho một từ; không có phần nào của chuỗi bí danh có thể được đưa vào lệnh
sau các đối số (ví dụ "Message"
:). Vì vậy, ví dụ, nếu tập lệnh chứa
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
đầu ra sẽ là
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
vì vậy bạn vẫn cần bật lại tùy chọn theo dõi sau khi hiển thị (các) thông báo - nhưng chỉ một lần sau mỗi khốiecho
lệnh liên tiếp :
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Sẽ thật tuyệt nếu chúng ta có thể set -x
tự động thực hiện sau một echo
- và chúng ta có thể, với một chút mánh khóe hơn. Nhưng trước khi tôi trình bày điều đó, hãy xem xét điều này. OP đang bắt đầu với các tập lệnh sử dụng #!/bin/sh -ex
shebang. Ngẫu nhiên người dùng có thể xóa x
khỏi shebang và có một tập lệnh hoạt động bình thường, không có dấu vết thực thi. Sẽ thật tốt nếu chúng ta có thể phát triển một giải pháp giữ lại tài sản đó. Một vài câu trả lời đầu tiên ở đây thất bại với tài sản đó bởi vì họ lần lượt truy tìm lại echo
mối quan hệ của Google sau khi tuyên bố, vô điều kiện, không liên quan đến việc nó đã được bật hay chưa.
Câu trả lời này rõ ràng không nhận ra vấn đề đó, vì nó thay thế echo
đầu ra với đầu ra theo dõi; do đó, tất cả các tin nhắn sẽ biến mất nếu tắt theo dõi. Bây giờ tôi sẽ trình bày một giải pháp bật lại dấu vết sau một echo
câu lệnh một cách có điều kiện - chỉ khi nó đã được bật. Việc hạ cấp điều này thành một giải pháp giúp truy tìm lại mối quan hệ của Google một cách vô điều kiện là chuyện nhỏ và bị bỏ lại như một bài tập.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-
là danh sách tùy chọn; ghép các chữ cái tương ứng với tất cả các tùy chọn được đặt. Ví dụ: nếu các tùy chọn e
và x
được đặt, thì đó $-
sẽ là một mớ chữ cái bao gồm e
và x
. Bí danh mới của tôi (ở trên) lưu giá trị của $-
trước khi tắt truy tìm. Sau đó, với dấu vết bị tắt, nó ném điều khiển vào một hàm shell. Hàm đó thực hiện echo
và sau đó kiểm tra xem liệu x
tùy chọn đã được bật khi bí danh được gọi hay chưa. Nếu tùy chọn được bật, chức năng sẽ bật lại; nếu nó bị tắt, chức năng sẽ tắt nó.
Bạn có thể chèn bảy dòng trên (tám, nếu bạn bao gồm một shopt
) ở đầu tập lệnh và để phần còn lại một mình.
Điều này sẽ cho phép bạn
- để sử dụng bất kỳ dòng shebang nào sau đây:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / shTHERx
hoặc chỉ đơn giản#! / thùng / sh
và nó sẽ hoạt động như mong đợi.
- để có mã như
(shebang)
lệnh 1
lệnh 2
lệnh 3
đặt -x
lệnh 4
lệnh 5
lệnh 6
đặt + x
lệnh 7
lệnh 8
lệnh 9
và
- Các lệnh 4, 5 và 6 sẽ được theo dõi - trừ khi một trong số chúng là một
echo
, trong trường hợp đó, nó sẽ được thực thi nhưng không được theo dõi. (Nhưng ngay cả khi lệnh 5 là một echo
, lệnh 6 vẫn sẽ được theo dõi.)
- Các lệnh 7, 8 và 9 sẽ không được theo dõi. Ngay cả khi lệnh 8 là một
echo
, lệnh 9 vẫn sẽ không được theo dõi.
- Các lệnh 1, 2 và 3 sẽ được theo dõi (như 4, 5 và 6) hoặc không (như 7, 8 và 9) tùy thuộc vào việc shebang có bao gồm hay không
x
.
Tái bút: Tôi đã phát hiện ra rằng, trên hệ thống của mình, tôi có thể bỏ builtin
từ khóa trong câu trả lời chính giữa của mình (từ khóa chỉ là bí danh echo
). Điều này không đáng ngạc nhiên; bash (1) nói rằng, trong quá trình mở rộng bí danh, chụp
Một từ giống hệt với một bí danh đang được mở rộng không được mở rộng lần thứ hai. Điều này có nghĩa rằng người ta có thể bí danh ls
để ls -F
, ví dụ, và bash không cố gắng một cách đệ quy mở rộng văn bản thay thế.
Không quá ngạc nhiên, câu trả lời cuối cùng (câu trả lời echo_and_restore
) không thành công nếu builtin
từ khóa bị bỏ qua 1 . Nhưng kỳ lạ là nó hoạt động nếu tôi xóa builtin
và chuyển thứ tự:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Nó dường như làm phát sinh hành vi không xác định. tôi đã nhìn thấy
- một vòng lặp vô hạn (có thể là do đệ quy không giới hạn),
- một
/dev/null: Bad address
thông báo lỗi và
- một bãi chứa lõi.
echo +x; echo "$*"; echo -x
bí danh, tôi muốn xem nó.