bash 스크립트가 실행될 때 특정 명령 만 인쇄하려면 어떻게해야합니까?


19

호출 할 때 전달하는 명령 줄 인수를 기반으로 다양한 if 문이있는 bash 스크립트가 있습니다. 어떤 명령이 실행되고 있는지에 대한 일종의 출력을 갖는 것은 모든 if 문을 통한 흐름을 확인하는 데 도움이되지만 현재 솔루션은 너무 많은 정보를 제공합니다.

set -v스크립트에서 사용 하는 것이 스크립트에서 실행될 때 화면에 인쇄 된 명령을 보는 데 다소 도움이되었지만 명령 이 너무 많습니다. 스크립트의 전체 사본과 거의 같습니다.

실행중인 명령을 보여주는 출력을 원하지만 if 문의 주석, 줄 바꿈, 표현식 등을보고 싶지 않습니다.

인쇄하기 전에 먼저 -v 옵션으로 생성 된 모든 가능한 출력을 정규식을 통해 전달할 수있는 방법이 있습니까? 또는 특정 "유형"의 명령 만 출력하도록 bash를 얻는 다른 솔루션 (예 : bash 특정 명령문, 주석 등이 아닌 실행 파일을 사용하는 것?)

[1] /programming/257616/sudo-changes-path-why 는 이것에 상당히 도움이되었으며 set -v사용법에 대한 제안을 얻었습니다 .

편집 :

내가 실행중인 스크립트와 비슷하지만 동일하지는 않은 스크립트 :

#!/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

이 스크립트에서 2 개의 가능한 출력 라인 세트 만 원합니다. 첫번째:

python ascript.py

두번째:

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

1
물론 파싱 할 수는 있지만 스크립트를 보여주고 set -v원하는 출력 부분과 원하지 않는 부분을 설명하지 않으면 도움 이되지 않습니다.
terdon

답변:


12

더 복잡한 bash 스크립트를 작성할 때 작은 함수를 사용하여 명령을 실행하여 명령을 로그 파일로 인쇄합니다.

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

그런 다음 스크립트에서 다음과 같은 명령을 실행합니다.

runthis "cp /foo/bar /baz/"

명령을 인쇄하지 않으려면 정상적으로 실행하십시오.

$LOG파일 이름을 설정 하거나 파일 이름을 제거하고 stdout 또는 stderr로 인쇄 할 수 있습니다.


+1 또한 짧은 이름의 함수 버전에 "중요한"명령을 추가하여 스크립트 내에서 이것을 실행할 수있었습니다. 따라서 v python ascript.py인용 부호로 묶지 않고 줄이
바뀌지 않고

@Trindaz 따옴표는 변수에 공백이 있으면 명령에 변수를 전달해야 할 때 나타납니다. 그렇지 않으면 문제가 발생할 수 있습니다.
terdon

eval ..... || ok=1: "eval ..."이 실패한 경우에만 "1"로 ok를 설정합니다 ?? 아마도 "&&"을 의미 했습니까? 그리고 그 의미라면, 평가 라인 앞에 "ok = 0"을 추가하면 매번 "재설정"됩니다. 또는 단순히 "ok"의 이름을 "error"로 바꾸십시오. 그것이 여기서 의미했던 것 같습니다. 결국 :eval "$@" 2>> "$LOG" && error=0 || error=1
Olivier Dulac

@OlivierDulac, 내가 사용하는 버전에는 ok명령이 실패하면 스크립트를 중지 시키는 변수가 있습니다. 여기서는 관련이 없으므로 삭제했지만을 삭제하는 것을 잊었습니다 || ok=1. 고마워, 지금 고쳐
terdon

훌륭한 솔루션! 나는 제거했다 "명령이 이미 둘러싸여 있기 때문에, 주위의 평가 문 "
gromit190

11

서브 쉘을 사용하십시오.

( set -x; cmd1; cmd2 )

예를 들면 다음과 같습니다.

( set -x; echo "hi there" )

인쇄물

+ echo 'hi there'
hi there

나는 set -x; cmd; set +x여러 가지 이유로 이것을 선호합니다 . 첫째, set -x이전에 켜져 있었던 경우 재설정되지 않습니다 . 둘째, 내부 스크립트 종료로 인해 상세 설정이 설정된 상태에서 트랩이 실행되지 않습니다.
올리버 곤자

2

@terdon과 비슷한 방법을 사용했습니다. 그것은 고급 프로그래밍 언어가 로거를 부르는 것의 시작이며 log4J (Java), log4Perl (Perl) 등과 같은 완전한 라이브러리로 제공합니다.

set -x앞에서 언급했듯이 Bash에서 비슷한 것을 사용할 수 있지만 코드 블록을 래핑하여 명령의 하위 세트 만 디버깅하도록 설정할 수 있습니다.

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

사용할 수있는 하나의 라이너 패턴이 있습니다.

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

스크립트의 여러 명령에 대해 이와 같이 줄 바꿈 할 수 있습니다.

set -x
cmd1
cmd2
set +x

cmd3

Log4Bash

대부분의 사람들은 모른다는하지만 배쉬는 또한뿐만 아니라 LOG4 *을 가지고 Log4Bash을 . 좀 더 겸손한 요구 사항이있는 경우이를 설정하는 데 시간이 걸릴 수 있습니다.

log4bash는 Bash 스크립트에 대한 로깅을 향상시키려는 시도입니다 (예 : Bash에 로깅을 줄임).

다음은 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

log4 * 프레임 워크의 강력한 기능으로 분류하려는 것을 원한다면 Log4sh 를 사용해보십시오.

발췌

log4sh는 원래 로깅이 너무 많거나 부족한 곳에서 일한 일부 프로덕션 환경에서 로깅 문제를 해결하기 위해 개발되었습니다. 특히 Cron 채용 공고는 모든 것이 효과가 있었거나 아무런 효과가 없었지만 자세한 이유는 아니라고 말하는 지속적이고 성가신 이메일로 인해 가장 두통을 일으켰습니다. 이제 쉘 스크립트에서 로깅하는 것이 중요하지만 단순한 "Hello, fix me!"이상이 필요한 환경에서 log4sh를 사용합니다. 로깅 메시지 유형. 당신이보고있는 것을 좋아하거나 개선에 대한 제안이 있으면, 저에게 이메일을 남겨주세요. 프로젝트에 대한 관심이 충분하면 더 발전시킬 것입니다.

log4sh는 Linux의 Bourne Again Shell (/ bin / bash)에서 개발되었지만 기본 Bourne Shell (/ bin / sh)에서 기본 프로덕션으로 작동하도록주의를 기울였습니다. 나 자신이 사용하는 플랫폼.

Log4sh는 Bash뿐만 아니라 여러 쉘을 지원합니다.

  • 본 셸 (sh)
  • 배쉬-GNU Bourne Again SHell (bash)
  • 대시 (대시)
  • 콘쉘 (ksh)
  • pdksh-공개 도메인 Korn 쉘 (pdksh)

또한 Linux뿐만 아니라 여러 OS에서 테스트되었습니다.

  • Cygwin (Windows에서)
  • FreeBSD (사용자 지원)
  • 리눅스 (Gentoo, RedHat, Ubuntu)
  • 맥 OS X
  • 솔라리스 8, 9, 10

log4 * 프레임 워크를 사용하는 데는 시간이 다소 걸리지 만 로깅에서 더 많은 요구가있는 경우에는 그만한 가치가 있습니다. Log4sh는 어 펜더를 정의하고 표시 될 출력 형식을 제어 할 수있는 구성 파일을 사용합니다.

#! /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'

이제 내가 실행할 때 :

$ ./log4sh.bash 
INFO - Hello, world

참고 : 위의 코드는 코드의 일부로 어 펜더를 구성합니다. 원하는 경우 자체 파일 log4sh.properties등 으로 추출 할 수 있습니다 .

자세한 내용이 필요하면 Log4sh에 대한 훌륭한 문서를 참조 하십시오.


추가 된 메모에 감사하지만, 내가 가진 주요 문제는 set소개해야 할 모든 명령, 주석 등을 번갈아 가며 스크립트 상단에 단일 문자 함수 호출이있는 함수를 갖는 것입니다. 스크립트의 모든 "중요한"줄은 지금 나에게 더 깔끔해 보였다. (함수는 하나의 문자 이름을 가지고 있기 때문에 단일 문자)
Trindaz

@Trindaz-죄송합니다. 아직 답변을 완료하지 못했습니다. terdon이 제공 한 기능이 더 필요한 경우 log4bash를 살펴보십시오.
slm

1
@Trindaz-때때로 비슷한 것을 수행합니다. 내가 사용한 다른 접근 방식 echo은 내 기능 을 래핑 mecho한 다음 -v일을 끄고 싶을 때 verbose 라는 프로그램으로 스위치를 전달하는 것입니다. 함수의 이름을 지정하는 두 번째 인수 스위치로 제어 할 수 있으므로 로깅을 제어 할 2 축이 있습니다. 이것은 종종 log4bash를 원하는 게이트웨이입니다.
slm

1
@Trindaz set -x는 명령이 실행될 때 이를 인쇄합니다. 주석을 인쇄하지 않습니다. set -x디버깅에 실용적입니다 ( set -v매우 유용하지는 않습니다). Zsh는 set -xbash보다 더 나은 출력을 제공 합니다. 예를 들어 현재 실행중인 함수와 소스 라인 번호를 보여줍니다.
Gilles 'SO- 악의를 멈춰라'

사실 @Gilles에게 감사합니다. 그러나이 경우에는 과장된 if 표현식 확장을 제공했습니다.
Trindaz

1

당신은 할 수 trap DEBUG후 테스트 변수를 . 이것을 스크립트 상단에 추가하십시오.BASH_COMMAND

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

trap 'log "$BASH_COMMAND"' DEBUG

코드는 읽을 수 있습니다. 첫 번째 인수가 pythonor로 시작하는지 테스트 pkill하고 그 경우에 인쇄합니다. 그리고 트랩은 BASH_COMMAND(실행될 명령을 포함하는) 첫 번째 인수로 사용합니다.

$ 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

case글로브 를 사용 하는 동안 쉽게 할 수 있습니다.

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

정규식을 사용하십시오.


0

이것은 Steven Penny의 깔끔한 기능의 수정 된 버전입니다. 인수를 컬러로 인쇄하고 필요에 따라 인용합니다. 이를 사용하여 추적하려는 명령을 선택적으로 에코하십시오. 따옴표가 출력되므로 스크립트를 디버깅하는 동안 인쇄 된 행을 복사하여 터미널에 붙여 넣어 즉시 다시 실행할 수 있습니다. 첫 번째 의견을 읽고 내가 변경 한 이유와 이유를 확인하십시오.

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
    }
  }
  ' "$@"
}

출력 사용 예 :

# 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

위의 두 번째 줄은 녹색으로 인쇄되며 세 번째 줄을 재현하기 위해 복사하여 붙여 넣을 수 있습니다.

추가 비고

@ Steven-Penny의 독창적 인 xc는 영리하며 모든 크레딧을받을 자격이 있습니다. 그러나 몇 가지 문제를 발견했지만 평판이 충분하지 않아서 자신의 게시물에 직접 댓글을 달 수 없었습니다. 그래서 나는 그의 게시물에 대해 제안 된 편집을했지만 검토 자들은 내 편집을 거부했습니다. 따라서 Steve Penny의 답변을 편집하는 것이 좋았지만이 답변으로 의견을 게시했습니다.

내가 스티븐 페니의 대답을 바꾸었던 것

고정 : null 문자열 인쇄-인쇄되지 않았습니다. 수정 : 문자열을 포함하여 인쇄하면 %awk 구문 오류가 발생했습니다. 전자가 배열 순회 순서를 보장하지 않기 때문에 로 대체 for (j in ...)되었습니다 for (j = 0, ...)(구현에 따라 다릅니다). 이식성을 위해 8 진수에 0을 추가했습니다.

최신 정보

스티븐 페니 (Steven Penny 's)는 그에 대한 답변에서 그 문제를 고쳤으므로,이 발언은 나의 답변에 대한 역사적 기록만을 유지합니다. 자세한 내용은 주석 섹션을 참조하십시오.


0

POSIX stdlib 라이브러리 의 "sh_trace"쉘 기능 을 사용하여 명령을 실행하기 전에 컬러로 인쇄 할 수 있습니다. 예:

시사

기본 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)
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.