Як я можу надрукувати лише певні команди зі скрипту bash під час їх запуску?


19

У мене є скрипт bash з різними, якщо висловлювання, засновані на аргументах командного рядка, я передаю при виклику. Маючи певний вихід щодо того, які команди виконуються, корисно підтвердити потік усіх тих, якщо заяви, але моє поточне рішення дає мені занадто багато інформації.

Використання set -vв скрипті було дещо корисним для перегляду команд, надрукованих на екрані під час виконання сценарію, проте я отримую занадто багато команд. Це майже як ціла копія сценарію.

Я хочу, щоб результат показував, які команди виконуються, але я не хочу бачити коментарі, нові рядки, вирази, якщо заяви і т.д.

Чи є спосіб я передати весь можливий висновок, згенерований опцією -v, спочатку через регулярний вираз перед тим, як надрукувати? Або якесь інше рішення отримати bash лише для вихідних команд певного "типу" (наприклад, що використовуються виконувані файли, а не просто bash конкретні заяви, коментарі тощо?)

[1] /programming/257616/sudo-changes-path- чому це було дуже корисно в цьому, і саме тут я отримав пропозицію щодо 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виводу ви хочете, а які - ні.
тердон

Відповіді:


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не потрібно вкладатись у цитати та втрачати виділення коду vim
Trindaz

@Trindaz цитати є, коли вам потрібно передавати змінні у ваших командах, якщо змінні містять пробіли, у вас можуть виникнути проблеми в іншому випадку.
тердон

eval ..... || ok=1: встановить "ОК" на "1" лише тоді, коли "eval ..." не вдасться ?? Можливо, ви мали на увазі "&&"? І якщо ви це мали на увазі, додайте "ok = 0" перед рядком eval, тож воно щоразу "скидається". Або просто перейменувати "добре" на "помилка"? здається, саме тут малося на увазі. Отже, врешті-решт:eval "$@" 2>> "$LOG" && error=0 || error=1
Олів’є Дулак

@OlivierDulac, у версії цього я використовую okзмінну, яка зупинить сценарій, якщо будь-яка команда не вдасться. Оскільки це не було актуальним, я видалив його, але забув видалити || ok=1. Дякую, виправлено зараз.
terdon

Відмінне рішення! Мені довелося видалити "оточуючий заяву eval, оскільки команда вже оточена "s
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's. Це початок того, що мови програмування вищого рівня називають реєстраторами, і пропонують як повноцінні бібліотеки, такі як 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

Більшість людей не звертає уваги, але Bash також має 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 завдав мені найбільших головних болів через їх постійні та дратівливі електронні листи, в яких говорилося, що все працює, або що нічого не працює, але не детальна причина. Зараз я використовую log4sh в середовищах, де вхід із скриптів оболонки є критичним, але там, де мені потрібно більше, ніж просто просте "Привіт, виправте мене!" тип повідомлення журналу. Якщо вам подобається те, що ви бачите, або є якісь пропозиції щодо вдосконалень, не соромтесь надіслати мені електронний лист. Якщо буде достатньо інтересу до проекту, я буду його розвивати далі.

log4sh був розроблений під оболонкою Bourne Again (/ bin / bash) в Linux, але велика увага була зроблена, щоб переконатися, що він працює під стандартною оболонкою Bourne Solaris (/ bin / sh), оскільки це відбувається в основному виробництві платформа, якою я користувався.

Log4sh підтримує декілька оболонок, не тільки Bash.

  • Борн Шелл (ш)
  • BASH - GNU Bourne Again SHell (удар)
  • DASH (тире)
  • Корн Шелл (кш)
  • pdksh - оболонка Korn для публічного домену (pdksh)

Його також перевіряли на декількох ОС, а не лише на Linux.

  • Cygwin (під Windows)
  • FreeBSD (підтримується користувачем)
  • Linux (Gentoo, RedHat, Ubuntu)
  • Mac 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 - вибачте, що ще не закінчив свою відповідь. Погляньте на log4bash, якщо у вас є більше потреб, ніж функція, яку надав тердон.
slm

1
@Trindaz - час від часу я роблю щось подібне, інший підхід, який я використовував, полягає в тому, щоб увімкнути echoсвою власну функцію mecho, а потім передати комутатор у програму, яка -vвимагає багатослівної роботи, коли я хочу вимкнути речі. Я також можу керувати ним за допомогою перемикача 2-го аргументу, який визначає назву функції, тому у мене є 2 осі, на яких можна керувати журналом. Це часто є шлюзом для бажання log4bash.
slm

1
@Trindaz set -xдрукує команди під час їх виконання. Він не друкує коментарів. set -xє практичним для налагодження (на відміну від, set -vякий не дуже корисний). Zsh має кращий вихід, set -xніж bash, наприклад, він показує, яка функція виконується в даний час і номер вихідного рядка.
Жил "ТАК - перестань бути злим"

Дякую @Gilles, що це правда, але це дало мені експансії if, які були надмірними в даному випадку
Trindaz

1

Ви могли б , trap DEBUGа потім перевірити на BASH_COMMANDзмінну . Додайте це до початку сценарію:

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

trap 'log "$BASH_COMMAND"' DEBUG

Код читається; він просто перевіряє, якщо перший аргумент починається з pythonабо 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

Це переглянута версія акуратної функції Стівена Пенні. Він друкує свої аргументи кольором і цитує їх за потребою. Використовуйте його, щоб вибірково повторювати команди, які ви хочете простежити. Оскільки лапки виводяться, ви можете скопіювати надруковані рядки та вставити їх у термінал для негайного повторного виконання під час налагодження сценарію. Прочитайте перший коментар, щоб знати, що я змінив і чому.

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

Другий рядок надрукується зеленим кольором і може бути скопійований для відтворення третього рядка.

Подальші зауваження

@ Оригінальний xc Стівен-Пенні розумний, і він заслуговує всіх кредитів за це. Однак я помітив деякі проблеми, але я не зміг прокоментувати його повідомлення безпосередньо, бо не маю достатньої репутації. Тому я вніс пропозицію змінити його допис, але рецензенти відхилили мою редакцію. Тому я вдався до публікації своїх коментарів як до цієї відповіді, хоча я вважав за краще відредагувати власну відповідь Стіва Пенні.

Що я змінив відповідь Стівена-Пенні

Виправлено: друк нульових рядків - вони не друкувалися. Виправлено: друкуючи рядки, що включають %- вони спричинили помилки синтаксису awk. Замінено for (j in ...)з , for (j = 0, ...)тому що колишній не гарантує порядок масиву обходу (це AWK залежить від реалізації). До восьмих номерів для переносимості додано 0.

Оновлення

З тих пір Стівен Пенні вирішив ці питання у своїй відповіді, тож ці зауваження залишаються лише історичним записом моєї відповіді. Детальнішу інформацію див. У розділі Коментарі.


0

Ви можете використовувати функцію оболонки "sh_trace" з бібліотеки stdlib POSIX для друку команди в кольорі перед її запуском. Приклад:

попередній перегляд

Основна функція 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)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.