2013-06-28 21 views
6

Piszę skrypt powłoki, który wykonuje pętlę nad niektórymi wartościami i uruchamia długi wiersz poleceń dla każdej wartości. Chciałbym wydrukować te polecenia po drodze, tak jak robi to make podczas uruchamiania pliku Makefile. Wiem, że mogłem po prostu "odbić" wszystkie polecenia przed ich uruchomieniem, ale wydaje mi się to nieeleganckie. Więc patrzę na set -x i podobnych mechanizmów Zamiast:jak wyłączyć dyskretnie xtrace w skrypcie powłoki?

#!/bin/sh 

for value in a long list of values 
do 
    set -v 
    touch $value # imagine a complicated invocation here 
    set +v 
done 

Mój problem jest: w każdej iteracji, nie tylko jest interresting linia wydrukowany, ale również linia set +x również. Czy można temu zapobiec? Jeśli nie, jakie obejście zalecasz?

PS: powyższy MWE używa sh, ale mam również zainstalowane bash i zsh w razie potrzeby.

+1

Możliwe duplikat [bash + X, przy czym nie jest drukowana] (http://stackoverflow.com/questions/13195655/bash-set-x-without-it-being-printed) – Beetle

Odpowiedz

6

Sandbox go w podpowłoce:

(set -x; do_thing_you_want_traced) 

Oczywiście, zmiany zmiennych lub środowiska wykonane w tej podpowłoce zostaną utracone.

Jeśli NAPRAWDĘ troszczysz się o to, możesz również użyć pułapki DEBUG (używając set -T, aby spowodować dziedziczenie funkcji), aby zaimplementować własny odpowiednik set -x.

Na przykład w przypadku stosowania bash

trap_fn() { 
    [[ $DEBUG && $BASH_COMMAND != "unset DEBUG" ]] && \ 
    printf "[%s:%s] %s\n" "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND" 
    return 0 # do not block execution in extdebug mode 
} 
trap trap_fn DEBUG 

DEBUG=1 
# ...do something you want traced... 
unset DEBUG 

Mimo to, emitujące BASH_COMMAND (pochłaniająca DEBUG można) nie są w pełni równoważne set -x; na przykład nie pokazuje wartości po rozwinięciu.

+0

Wielkie dzięki za odpowiedź! Nie gram ze zmiennymi w poleceniach (są to po prostu długie inwokacje), więc zastosowałem podejście podpowłok i idealnie pasuje do moich potrzeb. – Gyom

+0

wooo, fajny pomysł! :-) –

1

myślałem

set -x >/dev/null 2>1; echo 1; echo 2; set +x >/dev/null 2>&1 

ale dostał

+ echo 1 
1 
+ echo 2 
2 
+ 1> /dev/null 2>& 1 

Jestem zaskoczony tymi wynikami. ... ale

set -x ; echo 1; echo 2; set +x 
+ echo 1 
1 
+ echo 2 
2 

wygląda na spełnienie Twojego wymagania.

Widziałem podobne rezultaty, gdy kładę każde stwierdzenie na jedynej linii (z wyjątkiem zestawu + X)

IHTH.

+0

FYI - 'set -x' wyjście przechodzi tylko na stderr, chyba że zostanie przesłonięte BASH_XTRACEFD w bash 4. –

+0

... przy okazji, przebieg zmienia _indeed_ vary; Nie mogę odtworzyć opisanego tu zachowania na bash 4.2.45 (1). –

+0

@charlesDuffy: Używam ksh, ale czytam o bashu (tutaj) przez cały czas. Dzięki za szczegóły! Powodzenia wszystkim. – shellter

1

Chcesz spróbować użyć xtrace pojedynczej linii:

function xtrace() { 
    # Print the line as if xtrace was turned on, using perl to filter out 
    # the extra colon character and the following "set +x" line. 
    (
    set -x 
    # Colon is a no-op in bash, so nothing will execute. 
    : "[email protected]" 
    set +x 
) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2 
    # Execute the original line unmolested 
    "[email protected]" 
} 

Oryginalny polecenie wykonuje w tej samej powłoce pod transformacji tożsamości. Tuż przed uruchomieniem otrzymujesz nierekurencyjny xtrace argumentów. Pozwala to na xtrace poleceń, o które się troszczycie, bez spamowania stederr z duplikatami każdego polecenia "echo".

# Example 
for value in $long_list; do 
    computed_value=$(echo "$value" | sed 's/.../...') 
    xtrace some_command -x -y -z $value $computed_value ... 
done 
Powiązane problemy