Làm cách nào tôi chỉ có thể in một số lệnh nhất định từ tập lệnh bash khi chúng đang chạy?


19

Tôi có một tập lệnh bash với các câu lệnh if khác nhau dựa trên các đối số dòng lệnh mà tôi truyền vào khi gọi nó. Có một số loại đầu ra như những lệnh đang được chạy là hữu ích để xác nhận luồng qua tất cả các câu lệnh if, nhưng giải pháp hiện tại của tôi đang cung cấp cho tôi quá nhiều thông tin.

Sử dụng set -vtrong tập lệnh có phần hữu ích để xem các lệnh được in ra màn hình khi chúng được chạy trong tập lệnh, tuy nhiên tôi nhận được quá nhiều lệnh. Nó gần giống như toàn bộ bản sao của kịch bản.

Tôi muốn đầu ra cho thấy những lệnh nào đang được chạy, nhưng tôi không muốn thấy các bình luận, dòng mới, biểu thức trong câu lệnh if, v.v.

Có cách nào để tôi có thể vượt qua tất cả đầu ra có thể được tạo bởi tùy chọn -v thông qua biểu thức chính trước khi được in không? Hoặc một số giải pháp khác để nhận bash chỉ xuất các lệnh của một "loại" nhất định (ví dụ: đang sử dụng các tệp thực thi và không chỉ bash các câu lệnh, nhận xét cụ thể, v.v.?)

[1] /programming/257616/sudo-changes-path-why khá hữu ích về vấn đề này và là nơi tôi nhận được đề xuất cho việc set -vsử dụng.

Chỉnh sửa :

Một tập lệnh tương tự (nhưng không giống hệt) với tập lệnh tôi đang chạy:

#!/bin/bash

#get verbose command output
set -v

env=$1

if [ "$env" == "dev" ]; then
    python ascript.py
fi

if [ "$env" == "prod" ]; then

    #launching in prod will most likely fail if not run as root. Warn user if not running as root.
    if [ $EUID -ne 0 ]; then
        echo "It doesn't look like you're running me as root. This probably won't work. Press any key to continue." > /dev/stderr
        read input
    fi

    #"stop" any existing nginx processes
    pkill -f nginx

    nginx -c `pwd`/conf/artfndr_nginx.conf

fi

Tôi muốn chỉ có 2 bộ dòng đầu ra có thể từ tập lệnh này. Thứ nhất:

python ascript.py

Thư hai:

pkill -f nginx
nginx -c /some/current/directory/conf/artfndr_nginx.conf

1
Tất nhiên bạn có thể phân tích cú pháp nhưng chúng tôi không thể giúp trừ khi bạn cho chúng tôi xem kịch bản và giải thích phần nào của set -vđầu ra bạn muốn và phần nào bạn không.
terdon

Câu trả lời:


12

Khi tôi viết các tập lệnh bash phức tạp hơn, tôi sử dụng một hàm nhỏ để chạy các lệnh cũng sẽ in các lệnh chạy vào logfile:

runthis(){
    ## print the command to the logfile
    echo "$@" >> $LOG
    ## run the command and redirect it's error output
    ## to the logfile
    eval "$@" 2>> $LOG 
}

Sau đó, trong kịch bản của tôi, tôi chạy các lệnh như thế này:

runthis "cp /foo/bar /baz/"

Nếu bạn không muốn một lệnh được in, chỉ cần chạy bình thường.

Bạn có thể đặt $LOGtên tệp hoặc chỉ cần xóa nó và in thành thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn.


+1 Ngoài ra, tôi có thể chạy mã này trong tập lệnh của mình bằng cách chỉ cần thêm các lệnh "quan trọng" với phiên bản tên ngắn gọn của hàm, vì vậy các dòng trông giống như v python ascript.pykhông cần phải trích dẫn và làm nổi bật mã vim của tôi
Trindaz

@Trindaz các trích dẫn có sẵn khi bạn cần chuyển các biến trong các lệnh của mình, nếu các biến chứa khoảng trắng bạn có thể gặp vấn đề khác.
terdon

eval ..... || ok=1: sẽ đặt ok thành "1" chỉ khi "eval ..." không thành công ?? Có lẽ bạn có nghĩa là "&&"? Và nếu bạn có ý đó, hãy thêm "ok = 0" trước dòng eval, để nó "thiết lập lại" mỗi lần. Hoặc đơn giản là đổi tên "ok" thành "lỗi"? có vẻ như đó là những gì có nghĩa ở đây. Vì vậy, cuối cùng:eval "$@" 2>> "$LOG" && error=0 || error=1
Olivier Dulac

@OlivierDulac, trong phiên bản này tôi sử dụng, tôi có một okbiến sẽ dừng tập lệnh nếu bất kỳ lệnh nào thất bại. Vì điều đó không liên quan ở đây, tôi đã xóa nó nhưng quên xóa || ok=1. Cảm ơn, đã sửa ngay.
terdon

Giải pháp tuyệt vời! Tôi đã phải xóa "câu lệnh xung quanh, bởi vì lệnh đã được bao quanh bởi "s
gromit190

11

Sử dụng một vỏ phụ, tức là:

( set -x; cmd1; cmd2 )

Ví dụ:

( set -x; echo "hi there" )

in

+ echo 'hi there'
hi there

Tôi thích cái này hơn set -x; cmd; set +xvì nhiều lý do. Đầu tiên, nó không thiết lập lại set -xtrong trường hợp nó đã được bật trước đó. Thứ hai, chấm dứt tập lệnh bên trong không gây ra bẫy được thực thi với cài đặt dài dòng trên.
Oliver Gondža

2

Tôi đã thấy các phương thức được sử dụng tương tự như @ terdon's. Đó là sự khởi đầu của những gì mà các ngôn ngữ lập trình cấp cao hơn gọi là logger và cung cấp các thư viện đầy đủ, chẳng hạn như log4J (Java), log4Perl (Perl), v.v.

Bạn có thể nhận được một cái gì đó tương tự bằng cách sử dụng set -xtrong Bash như bạn đã đề cập nhưng bạn có thể sử dụng nó để bật gỡ lỗi chỉ là một tập hợp con các lệnh bằng cách gói các khối mã với chúng như vậy.

$ set -x; cmd1; cmd2; set +x

Ví dụ

Đây là một mẫu lót bạn có thể sử dụng.

$ set -x; echo  "hi" ;set +x
+ echo hi
hi
+ set +x

Bạn có thể gói chúng như thế này cho nhiều lệnh trong một tập lệnh.

set -x
cmd1
cmd2
set +x

cmd3

Log4Bash

Hầu hết mọi người đều không biết nhưng Bash cũng có log4 *, Log4Bash . Nếu bạn có nhu cầu khiêm tốn hơn, điều này có thể đáng để dành thời gian để thiết lập nó.

log4bash là một nỗ lực để ghi nhật ký tốt hơn cho các tập lệnh Bash (nghĩa là làm cho việc đăng nhập vào Bash trở nên ít hơn).

Ví dụ

Dưới đây là một số ví dụ về việc sử dụng log4bash.

#!/usr/bin/env bash
source log4bash.sh

log "This is regular log message... log and log_info do the same thing";

log_warning "Luke ... you turned off your targeting computer";
log_info "I have you now!";
log_success "You're all clear kid, now let's blow this thing and go home.";
log_error "One thing's for sure, we're all gonna be a lot thinner.";

# If you have figlet installed -- you'll see some big letters on the screen!
log_captains "What was in the captain's toilet?";

# If you have the "say" command (e.g. on a Mac)
log_speak "Resistance is futile";

Log4sh

Nếu bạn muốn những gì tôi sẽ phân loại thành toàn bộ sức mạnh của khung log4 * thì tôi sẽ thử Log4sh .

đoạn trích

log4sh ban đầu được phát triển để giải quyết vấn đề đăng nhập mà tôi gặp phải trong một số môi trường sản xuất mà tôi đã làm việc ở nơi tôi có quá nhiều việc đăng nhập, hoặc không đủ. Công việc cron nói riêng khiến tôi đau đầu nhất với những email liên tục và khó chịu của họ nói với tôi rằng mọi thứ đều hoạt động, hoặc không có gì hiệu quả nhưng không phải là lý do chi tiết tại sao. Bây giờ tôi sử dụng log4sh trong các môi trường mà việc đăng nhập từ shell script là rất quan trọng, nhưng nơi tôi cần nhiều hơn chỉ là một câu "Xin chào, hãy sửa tôi!" loại thông điệp đăng nhập. Nếu bạn thích những gì bạn thấy hoặc có bất kỳ đề xuất nào về các cải tiến, xin vui lòng gửi email cho tôi. Nếu có đủ sự quan tâm đến dự án, tôi sẽ phát triển nó hơn nữa.

log4sh đã được phát triển theo Bourne Again Shell (/ bin / bash) trên Linux, nhưng phải hết sức cẩn thận để đảm bảo nó hoạt động theo Bourne Shell of Solaris (/ bin / sh) mặc định vì đây là sản phẩm chính nền tảng được sử dụng bởi chính tôi.

Log4sh hỗ trợ một số shell, không chỉ Bash.

  • Vỏ Bourne (sh)
  • BASH - GNU Bourne Again SHell (bash)
  • DASH (dấu gạch ngang)
  • Korn Shell (ksh)
  • pdksh - Tên miền Korn Shell (pdksh)

Nó cũng đã được thử nghiệm trên một số hệ điều hành, không chỉ Linux.

  • Cygwin (trong Windows)
  • FreeBSD (hỗ trợ người dùng)
  • Linux (Gentoo, RedHat, Ubuntu)
  • Mac OS X
  • Solaris 8, 9, 10

Sử dụng khung log4 * sẽ mất một chút thời gian để tìm hiểu nhưng nó đáng giá nếu bạn có nhu cầu khắt khe hơn từ việc đăng nhập của mình. Log4sh sử dụng tệp cấu hình nơi bạn có thể xác định các phần bổ sung và kiểm soát định dạng cho đầu ra sẽ xuất hiện.

Thí dụ

#! /bin/sh
#
# log4sh example: Hello, world
#

# load log4sh (disabling properties file warning) and clear the default
# configuration
LOG4SH_CONFIGURATION='none' . ./log4sh
log4sh_resetConfiguration

# set the global logging level to INFO
logger_setLevel INFO

# add and configure a FileAppender that outputs to STDERR, and activate the
# configuration
logger_addAppender stderr
appender_setType stderr FileAppender
appender_file_setFile stderr STDERR
appender_activateOptions stderr

# say Hello to the world
logger_info 'Hello, world'

Bây giờ khi tôi chạy nó:

$ ./log4sh.bash 
INFO - Hello, world

LƯU Ý: Phần trên cấu hình appender như một phần của mã. Nếu bạn thích điều này có thể được trích xuất ra thành tập tin riêng của nó, log4sh.propertiesv.v.

Tham khảo tài liệu tuyệt vời cho Log4sh nếu bạn cần thêm chi tiết.


Cảm ơn các ghi chú đã thêm, nhưng vấn đề chính tôi gặp phải đó là tất cả các setlệnh tôi cần giới thiệu, xen kẽ xung quanh các bình luận, v.v. bây giờ tất cả các dòng "quan trọng" trong kịch bản dường như gọn gàng hơn đối với tôi. (ký tự đơn vì hàm có một tên ký tự)
Trindaz 27/12/13

@Trindaz - xin lỗi tôi chưa hoàn thành câu trả lời của mình. Hãy xem log4bash nếu bạn có nhiều nhu cầu mà chức năng mà terdon đưa ra.
slm

1
@Trindaz - Thỉnh thoảng tôi cũng làm một cái gì đó tương tự, cách tiếp cận khác tôi đã sử dụng là bọc echochức năng của chính mình mecho, và sau đó chuyển một công tắc vào chương trình được gọi là -vdài dòng khi tôi muốn tắt mọi thứ. Tôi cũng có thể điều khiển nó bằng một công tắc đối số thứ 2 chỉ định tên của hàm, vì vậy tôi có 2 trục để điều khiển ghi nhật ký. Đây thường là cổng để muốn log4bash.
slm

1
@Trindaz set -xin các lệnh khi chúng được thực thi. Nó không in bình luận. set -xlà thực tế để gỡ lỗi (không giống như set -vkhông hữu ích). Zsh có đầu ra tốt set -xhơn so với bash, ví dụ, nó cho thấy chức năng nào hiện đang được thực thi và số dòng nguồn.
Gilles 'SO- ngừng trở nên xấu xa'

Cảm ơn @Gilles là sự thật, nhưng nó đã cho tôi mở rộng nếu biểu thức, quá mức cần thiết trong trường hợp này
Trindaz

1

Bạn có thể trap DEBUGvà sau đó kiểm tra các BASH_COMMANDbiến . Thêm phần này vào đầu tập lệnh:

log() {
    case "$1" in
        python\ *)
            ;&
        pkill\ *)
            printf "%s\n" "$*"
            ;;
    esac
}

trap 'log "$BASH_COMMAND"' DEBUG

Mã này có thể đọc được; nó chỉ kiểm tra nếu đối số đầu tiên bắt đầu bằng pythonhoặc pkill, và in nó nếu đó là trường hợp. Và cái bẫy sử dụng BASH_COMMAND(chứa lệnh sẽ được thực thi) làm đối số đầu tiên.

$ bash foo.sh dev
python ascript.py
python: can't open file 'ascript.py': [Errno 2] No such file or directory
$ bash foo.sh prod
It doesn't look like you're running me as root. This probably won't work. Press any key to continue.

pkill -f nginx
foo.sh: line 32: nginx: command not found

Lưu ý rằng trong khi casesử dụng các khối, bạn có thể dễ dàng thực hiện:

if [[ $1 =~ python|nginx ]]
then
    printf "%s" "$*"
fi

Và sử dụng các biểu thức thông thường.


0

Đây là phiên bản sửa đổi của chức năng gọn gàng của Steven Penny. Nó in các đối số của nó bằng màu sắc và trích dẫn chúng khi cần thiết. Sử dụng nó để lặp lại có chọn lọc các lệnh bạn muốn theo dõi. Vì các trích dẫn là đầu ra, bạn có thể sao chép các dòng in và dán chúng vào thiết bị đầu cuối để thực hiện lại ngay lập tức trong khi bạn đang gỡ lỗi một tập lệnh. Đọc bình luận đầu tiên để biết những gì tôi đã thay đổi và tại sao.

xc() # $@-args
{
  cecho "$@"
  "$@"
}
cecho() # $@-args
{
  awk '
  BEGIN {
    x = "\047"
    printf "\033[36m"
    while (++i < ARGC) {
      if (! (y = split(ARGV[i], z, x))) {
        printf (x x)
      } else {
        for (j = 1; j <= y; j++) {
          printf "%s", z[j] ~ /[^[:alnum:]%+,./:=@_-]/ ? (x z[j] x) : z[j]
          if (j < y) printf "\\" x
        }
      }
      printf i == ARGC - 1 ? "\033[m\n" : FS
    }
  }
  ' "$@"
}

Ví dụ sử dụng với đầu ra:

# xc echo "a b" "c'd" "'" '"' "fg" '' " " "" \# this line prints in green

echo 'a b' c\'d \' '"' fg '' ' ' '' '#' this line prints in green

a b c'd ' " fg # this line prints in green

Dòng thứ hai ở trên in màu xanh lá cây và có thể được sao chép để sao chép dòng thứ ba.

Nhận xét thêm

@ Xc ban đầu của Steven-Penny rất thông minh và anh ấy xứng đáng với tất cả các khoản tín dụng cho nó. Tuy nhiên, tôi nhận thấy một số vấn đề, nhưng tôi không thể bình luận trực tiếp bài đăng của anh ấy vì tôi không có đủ danh tiếng. Vì vậy, tôi đã thực hiện một chỉnh sửa được đề xuất cho bài viết của anh ấy nhưng những người đánh giá đã từ chối chỉnh sửa của tôi. Do đó, tôi đã dùng đến việc đăng bình luận của mình dưới dạng câu trả lời này, mặc dù tôi muốn có thể chỉnh sửa câu trả lời của Steve Penny.

Những gì tôi đã thay đổi câu trả lời của Steven-Penny

Đã sửa: in chuỗi null - chúng không được in. Đã sửa lỗi: in chuỗi bao gồm %- chúng gây ra lỗi cú pháp awk. Thay thế for (j in ...)bằng for (j = 0, ...)bởi vì trước đây không đảm bảo trật tự của mảng traversal (nó awk thực hiện phụ thuộc). Đã thêm 0 vào số bát phân cho tính di động.

Cập nhật

Kể từ đó, Steven Penny đã sửa những vấn đề đó trong câu trả lời của anh ấy, vì vậy những nhận xét này chỉ dành cho hồ sơ lịch sử về câu trả lời của tôi. Xem phần Nhận xét để biết thêm chi tiết.


0

Bạn có thể sử dụng hàm shell "sh_trace" từ thư viện POSIX stdlib để in lệnh bằng màu trước khi chạy nó. Thí dụ:

xem trước

Chức năng Awk:

function sh_trace(ary,   b, d, k, q, w, z) {
  b = "\47"
  for (d in ary) {
    k = split(ary[d], q, b)
    q[1]
    if (d - 1)
      z = z " "
    for (w in q) {
      z = z (!k || q[w] ~ "[^[:alnum:]%+,./:=@_-]" ? b q[w] b : q[w]) \
      (w < k ? "\\" b : "")
    }
  }
  printf "\33[36m%s\33[m\n", z
  system(z)
}
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.