2012-09-01 22 views
14

Có cách nào để bash vào một loại chế độ tiết ở đâu, như vậy, khi nó chạy một kịch bản lệnh shell, nó lặp lại lệnh mà nó sẽ chạy trước khi chạy nó? Nghĩa là, để có thể thấy các lệnh được chạy (cũng như đầu ra của chúng), tương tự như đầu ra của make?Lệnh Echo, sau đó chạy nó? (Giống như make)

Nghĩa là, nếu chạy một kịch bản shell như

echo "Hello, World" 

Tôi muốn đầu ra sau đây

echo "Hello, World" 
Hello, World 

Ngoài ra, là nó có thể viết một hàm bash gọi echo_and_run rằng sẽ ra một lệnh và sau đó chạy nó?

$ echo_and_run echo "Hello, World" 
echo "Hello, World" 
Hello, World 

Trả lời

5

Có thể sử dụng bash của printf kết hợp với sự xác định định dạng %q để thoát khỏi những lập luận để không gian được bảo quản:

function echo_and_run { 
    echo "$" "[email protected]" 
    eval $(printf '%q ' "[email protected]") < /dev/tty 
} 
22

Bạn có thể thực hiện chức năng của riêng mình thành echo lệnh trước khi gọi eval.

Bash cũng có tính năng gỡ lỗi. Khi bạn set -x bash sẽ hiển thị mỗi lệnh trước khi thực hiện lệnh.

[email protected]:~/dir$ set -x 
[email protected]:~/dir$ ls 
+ ls --color=auto 
a b c d e f 
+1

+1 và cũng có thể, nếu nó không rõ ràng, 'thiết -x' cũng có thể đi trong vỏ tập lệnh và sẽ kéo dài thời lượng của tập lệnh. – jedwards

+0

Điều này dường như là cách tiếp cận tốt nhất, đáng tin cậy nhất. (Và cũng làm việc với chuyển hướng, mà tôi đã chuẩn bị để không lo lắng về, mặc dù nó là tốt đẹp để có.) Vấn đề duy nhất là 'set + x' lệnh xuất hiện trong đầu ra cũng ... Cũng phát hiện ra điều này: [Tôi muốn một nhật ký các hành động của tập lệnh của tôi] (http://mywiki.wooledge.org/BashFAQ/050). – mjs

+3

@mjs: Nếu bạn muốn lệnh echo-ing cho toàn bộ thời gian chạy của tập lệnh, bạn có thể chạy nó thông qua 'bash -x' (cho phép' đặt -x' hoàn toàn và không xuất nó). –

-1

Tạo tập lệnh cơ bản (+ x) có tên là "echo_and_run" với tập lệnh shell đơn giản được đề cập dưới đây!

#!/bin/bash 
echo "$1" 
$1 

$ ./echo_and_run "echo Hello, World"

echo Hello, World 
Hello, World 

Tuy nhiên, approch cnicutar để set -x là đáng tin cậy và khuyến khích mạnh mẽ.

+0

Không, làm 'echo" $ @ "; "$ @" ' –

+0

Dấu nháy này - ví dụ ở trên, bạn nhận được' echo Hello, World' thay vì 'echo" Hello, World "'. – mjs

+0

Phải, nếu chúng ta sử dụng "$ @", nó nuốt dấu ngoặc kép. người ta có thể sử dụng một cái gì đó như, './echo_and_run 'echo" Xin chào, thế giới "'' – Mayura

13

Để trả lời phần thứ hai của câu hỏi của bạn, đây là một chức năng vỏ mà những gì bạn muốn:

echo_and_run() { echo "[email protected]" ; "[email protected]" ; } 

tôi sử dụng một cái gì đó tương tự như sau:

echo_and_run() { echo "\$ [email protected]" ; "[email protected]" ; } 

mà in $ trước lệnh (nó trông giống như một dấu nhắc trình bao và làm cho nó rõ ràng hơn rằng đó là một lệnh). Tôi đôi khi sử dụng điều này trong các kịch bản khi tôi muốn hiển thị một số (nhưng không phải tất cả) các lệnh mà nó đang thực hiện.

Như những người khác đã đề cập, nó không mất dấu ngoặc kép:

$ echo_and_run echo "Hello, world" 
$ echo Hello, world 
Hello, world 
$ 

nhưng tôi không nghĩ rằng có bất kỳ cách tốt để tránh điều đó; dải dấu ngoặc kép trước khi echo_and_run có cơ hội để xem chúng. Bạn có thể viết một kịch bản lệnh sẽ kiểm tra các đối số chứa dấu cách và các siêu ký tự shell khác và thêm dấu ngoặc kép nếu cần (mà vẫn không nhất thiết phải khớp với dấu ngoặc kép mà bạn thực sự đã gõ).

+0

Có cách nào để xử lý nhiều lệnh trên một dòng không? I.e 'echo_and_run cd .. && ls' chạy cả hai lệnh, nhưng chỉ các kết quả đầu ra' $ cd ..' – MrTheWalrus

+1

@MrTheWalrus: Đó là vì chỉ 'cd ..' được truyền làm đối số cho hàm' echo_and_run() '. Nó giống như gõ 'echo_and_run cd ..' theo sau bởi' ls'. Bí quyết là đưa nó vào 'echo_and_run' * dưới dạng một lệnh *:' echo_and_run sh -c 'cd .. && ls''. Thay thế '/ bin/sh' bằng'/bin/bash' nếu bạn cần các tính năng bash-cụ thể (hoặc ksh, hoặc zsh, hoặc ...) –

+0

Cảm ơn. Tôi có thể nói vấn đề là gì, nhưng không biết làm thế nào để nó xử lý toàn bộ dòng như một lệnh duy nhất. – MrTheWalrus

0

Để thêm vào hiện thực của người khác, đây là kịch bản soạn sẵn cơ bản của tôi, trong đó có tranh cãi phân tích cú pháp (điều quan trọng nếu bạn đang chuyển đổi cấp độ độ dài).

#!/bin/sh 

# Control verbosity 
VERBOSE=0 

# For use in usage() and in log messages 
SCRIPT_NAME="$(basename $0)" 

ARGS=() 

# Usage function: tells the user what's up, then exits. ALWAYS implement this. 
# Optionally, prints an error message 
# usage [{errorLevel} {message...} 
function usage() { 
    local RET=0 
    if [ $# -gt 0 ]; then 
     RET=$1; shift; 
    fi 
    if [ $# -gt 0 ]; then 
     log "[$SCRIPT_NAME] ${@}" 
    fi 
    log "Describe this script" 
    log "Usage: $SCRIPT_NAME [-v|-q]" # List further options here 
    log " -v|--verbose Be more verbose" 
    log " -q|--quiet  Be less verbose" 
    exit $RET 
} 

# Write a message to stderr 
# log {message...} 
function log() { 
    echo "${@}" >&2 
} 

# Write an informative message with decoration 
# info {message...} 
function info() { 
    if [ $VERBOSE -gt 0 ]; then 
     log "[$SCRIPT_NAME] ${@}" 
    fi 
} 

# Write an warning message with decoration 
# warn {message...} 
function warn() { 
    if [ $VERBOSE -gt 0 ]; then 
     log "[$SCRIPT_NAME] Warning: ${@}" 
    fi 
} 

# Write an error and exit 
# error {errorLevel} {message...} 
function error() { 
    local LEVEL=$1; shift 
    if [ $VERBOSE -gt -1 ]; then 
     log "[$SCRIPT_NAME] Error: ${@}" 
    fi 
    exit $LEVEL 
} 

# Write out a command and run it 
# vexec {minVerbosity} {prefixMessage} {command...} 
function vexec() { 
    local LEVEL=$1; shift 
    local MSG="$1"; shift 
    if [ $VERBOSE -ge $LEVEL ]; then 
     echo -n "$MSG: " 
     local CMD=() 
     for i in "${@}"; do 
      # Replace argument's spaces with ''; if different, quote the string 
      if [ "$i" != "${i/ /}" ]; then 
       CMD=(${CMD[@]} "'${i}'") 
      else 
       CMD=(${CMD[@]} $i) 
      fi 
     done 
     echo "${CMD[@]}" 
    fi 
    ${@} 
} 

# Loop over arguments; we'll be shifting the list as we go, 
# so we keep going until $1 is empty 
while [ -n "$1" ]; do 
    # Capture and shift the argument. 
    ARG="$1" 
    shift 
    case "$ARG" in 
     # User requested help; sometimes they do this at the end of a command 
     # while they're building it. By capturing and exiting, we avoid doing 
     # work before it's intended. 
     -h|-\?|-help|--help) 
      usage 0 
      ;; 
     # Make the script more verbose 
     -v|--verbose) 
      VERBOSE=$((VERBOSE + 1)) 
      ;; 
     # Make the script quieter 
     -q|--quiet) 
      VERBOSE=$((VERBOSE - 1)) 
      ;; 
     # All arguments that follow are non-flags 
     # This should be in all of your scripts, to more easily support filenames 
     # that start with hyphens. Break will bail from the `for` loop above. 
     --) 
      break 
      ;; 
     # Something that looks like a flag, but is not; report an error and die 
     -?*) 
      usage 1 "Unknown option: '$ARG'" >&2 
      ;; 
     # 
     # All other arguments are added to the ARGS array. 
     *) 
      ARGS=(${ARGS[@]} "$ARG") 
      ;; 
    esac 
done 
# If the above script found a '--' argument, there will still be items in $*; 
# move them into ARGS 
while [ -n "$1" ]; do 
    ARGS=(${ARGS[@]} "$1") 
    shift 
done 

# Main script goes here. 

Later ...

vexec 1 "Building myapp.c" \ 
    gcc -c myapp.c -o build/myapp.o ${CFLAGS} 

Lưu ý: Điều này sẽ không bao gồm các lệnh bằng đường ống; bạn cần phải bash -c những thứ đó, hoặc chia chúng thành các biến hoặc tệp trung gian.

0

Hai tùy chọn hữu ích vỏ có thể được bổ sung vào dòng bash lệnh hoặc thông qua lệnh set trong một kịch bản hoặc phiên tương tác:

  • -v dòng đầu vào In vỏ khi chúng được đọc.
  • -x Sau khi mở rộng mỗi lệnh đơn giản, for lệnh, case lệnh, select lệnh, hoặc số học for lệnh, hiển thị giá trị mở rộng của PS4, tiếp theo là các lệnh và nó mở rộng đối số hoặc danh sách từ liên quan.
0

Đối với timestamps thêm và I/O thông tin, xem xét các lệnh annotate-output từ devscripts gói Debian 's:

annotate-output echo hello 

Output:

13:19:08 I: Started echo hello 
13:19:08 O: hello 
13:19:08 I: Finished with exitcode 0 

Bây giờ nhìn đối với tệp không tồn tại, và lưu ý E: cho STDERR đầu ra:

annotate-output ls nosuchfile 

Output:

13:19:48 I: Started ls nosuchfile 
13:19:48 E: ls: cannot access 'nosuchfile': No such file or directory 
13:19:48 I: Finished with exitcode 2 
Các vấn đề liên quan