bash: keluar dari setiap baris dari `-x` yang bergema

11

Di bash, ketika menjalankan dengan -xopsi, apakah mungkin untuk mengecualikan perintah individual dari gema?

Saya mencoba membuat output serapi mungkin, jadi saya menjalankan bagian-bagian tertentu dari skrip saya dengan subkulit set +x. Namun, baris set +xitu sendiri masih bergema dan tidak menambahkan informasi berharga ke output.

Saya ingat kembali pada masa lalu yang buruk .bat, ketika berlari dengan echo on, garis individu dapat dikecualikan dengan memulai dengan @. Apakah ada yang setara dalam bash?

#!/bin/bash -x

function i_know_what_this_does() {
  (
    set +x
    echo do stuff
  )
}

echo the next-next line still echoes 'set +x', is that avoidable?
i_know_what_this_does
echo and we are back and echoing is back on

Saat menjalankan hal di atas, output adalah:

+ echo the next-next line still echoes 'set +x,' is that 'avoidable?'
the next-next line still echoes set +x, is that avoidable?
+ i_know_what_this_does
+ set +x
do stuff
+ echo and we are back and echoing is back on
and we are back and echoing is back on
klak
sumber

Jawaban:

22

xtraceoutput masuk ke stderr, jadi Anda bisa mengarahkan ulang stderrke /dev/null:

i_know_what_this_does() {
  echo do stuff
} 2> /dev/null

Jika Anda masih ingin melihat kesalahan dari perintah yang dijalankan di dalam fungsi, Anda bisa melakukannya

i_know_what_this_does() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

Perhatikan penggunaan (...)alih - alih {...}untuk menyediakan cakupan lokal untuk fungsi tersebut melalui subkulit. bash, karena versi 4.4 sekarang mendukung local -seperti pada shell Almquist untuk membuat opsi lokal ke fungsi (mirip dengan set -o localoptionsdi zsh), sehingga Anda dapat menghindari subkulit dengan melakukan:

i_know_what_this_does() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Alternatif untuk bash4.0 hingga 4.3 adalah menggunakan $BASH_XTRACEFDvariabel dan membuka deskriptor file khusus /dev/nulluntuk itu:

exec 9> /dev/null
set -x
i_know_what_this_does() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Karena bashtidak memiliki kemampuan untuk menandai fd dengan flag close-on-exec , yang memiliki efek samping bocornya fd ke perintah lain.

Lihat juga locvar.sh ini yang berisi beberapa fungsi untuk mengimplementasikan ruang lingkup lokal untuk variabel dan fungsi dalam skrip POSIX dan juga menyediakan trace_fndan untrace_fnfungsi untuk membuatnya xtrace d atau tidak.

Stéphane Chazelas
sumber
Manis! Saya mencari untuk melihat apakah ada pengubah yang dapat saya terapkan pada fungsi itu sendiri, tetapi saya tidak berpikir tentang hanya mengarahkan ulang stderr. Terima kasih!
clacke
1
Btw, stchaz.free.fr/which_interpreter dari halaman yang sama cukup mengagumkan dan mengganggu. :-)
clacke
Dan sekarang saya kembali lagi ke sini untuk metode kedua, membungkam set + x tanpa membungkam keluaran stderr yang berguna. Terima kasih lagi!
clacke
2

Alasan yang set +xdicetak adalah itu set -xberarti "cetak perintah yang akan Anda jalankan, dengan ekspansi, sebelum menjalankannya . Jadi shell tidak tahu bahwa Anda ingin tidak mencetak apa-apa sampai setelah mencetak garis yang mengatakan tidak untuk mencetak hal-hal. Sejauh pengetahuan saya, tidak ada cara untuk menghentikan hal itu terjadi.

Jenny D
sumber
0

Inilah solusi yang telah Anda cari:

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.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

Perintah asli dijalankan di shell yang sama di bawah transformasi identitas. Tepat sebelum berjalan, Anda mendapatkan xtrace non-rekursif dari argumen. Ini memungkinkan Anda untuk melacak perintah yang Anda pedulikan tanpa mengirim spam kepada stederr dengan duplikat salinan setiap perintah "echo".

# Example
echo "About to do something complicated ..."
xtrace do_something_complicated
Dave Dopson
sumber
Atau untuk menghindari perl(dan masalah dengan perintah multi-line):+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
Stéphane Chazelas
Tidak, maaf, unix.stackexchange.com/a/60049/17980 adalah solusi yang saya cari. :-) Apakah set -xmanuver membelikan saya sesuatu yang sebanding dengan hanya printf >&2 '+ %s\n' "$*"?
clacke
Seperti dalam:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
clacke