Menekan jejak eksekusi bash (set -x) dari luar skrip


17

Saya mencoba menemukan jawaban untuk pertanyaan ini, tetapi sejauh ini tidak berhasil:

Saya memiliki skrip yang menjalankan beberapa skrip lain, dan banyak skrip lainnya memiliki "set -x" di dalamnya, yang membuat mereka mencetak setiap perintah yang mereka jalankan. Saya ingin menyingkirkan itu tetapi menyimpan informasi jika ada skrip yang mengirim pesan kesalahan ke stderr.

Jadi saya tidak bisa begitu saja menulis ./script 2>/dev/null

Selain itu, saya tidak memiliki hak istimewa untuk mengedit skrip-skrip lain itu, jadi saya tidak bisa mengubah opsi setel secara manual.

Saya sedang berpikir tentang mencatat semuanya dari stderr ke file yang terpisah dan menyaring perintah penelusuran, tapi mungkin ada cara yang lebih sederhana?


1
./script 2>some_file
Satō Katsura

Jawaban:


25

Dengan bash4.1 ke atas, Anda bisa melakukannya

BASH_XTRACEFD=7 ./script.bash 7> /dev/null

(juga berfungsi saat bashdipanggil sebagai sh).

Pada dasarnya, kami menyuruh bashoutput xtraceoutput pada file descriptor 7 bukannya default 2, dan mengarahkan file descriptor ke /dev/null. Nomor fd sewenang-wenang. Gunakan fd di atas 2 yang tidak digunakan dalam skrip Anda. Jika shell yang Anda masukkan perintah ini adalah bashatau yash, Anda bahkan dapat menggunakan angka di atas 9 (meskipun Anda dapat mengalami masalah jika deskriptor file digunakan secara internal oleh shell).

Jika shell yang Anda gunakan bashuntuk skrip itu zsh, Anda juga dapat melakukan:

(export BASH_XTRACEFD; ./script.bash {BASH_XTRACEFD}> /dev/null)

untuk variabel yang secara otomatis diberikan fd gratis pertama di atas 9.

Untuk versi yang lebih lama dari bash, opsi lain, jika xtracedihidupkan dengan set -x(sebagai lawan #! /bin/bash -xatau set -o xtrace) akan mendefinisikan kembali setsebagai fungsi yang diekspor yang tidak melakukan apa-apa ketika disahkan -x(meskipun itu akan merusak skrip jika (atau bashskrip lain yang diminta) digunakan setuntuk mengatur parameter posisi).

Suka:

set()
  case $1 in
    (-x) return 0;;
    (-[!-]|"") builtin set "$@";;
    (*) echo >&2 That was a bad idea, try something else; builtin set "$@";;
  esac

export -f set
./script.bash

Pilihan lain adalah menambahkan perangkap DEBUG dalam $BASH_ENVfile yang dilakukan set +xsebelum setiap perintah.

echo 'trap "{ set +x; } 2>/dev/null" DEBUG' > ~/.no-xtrace
BASH_ENV=~/.no-xtrace ./script.bash

Itu tidak akan bekerja ketika set -xdilakukan di sub-shell.

Seperti yang dikatakan @ilkkachu, asalkan Anda memiliki izin menulis ke folder apa pun di sistem file, Anda setidaknya harus dapat membuat salinan skrip dan mengeditnya.

Jika tidak ada tempat Anda dapat menulis salinan skrip, atau jika tidak nyaman membuat dan mengedit salinan baru setiap kali ada pembaruan untuk skrip asli, Anda mungkin masih dapat melakukan:

 bash <(sed 's/set -x/set +x/g' ./script.bash)

Itu (dan pendekatan penyalinan) mungkin tidak berfungsi dengan baik jika skrip melakukan sesuatu yang disukai $0atau variabel khusus seperti $BASH_SOURCE(seperti mencari file yang relatif terhadap lokasi skrip itu sendiri), jadi Anda mungkin perlu melakukan beberapa pengeditan seperti ganti $0dengan jalur skrip ...


Jawaban pertama Anda adalah apa yang saya butuhkan, bersih dan elegan. Bisakah Anda jelaskan sedikit bagaimana cara kerjanya? Kenapa angka 7? Untuk apa nomor lain dapat digunakan? Terima kasih.
manusia

@human, lihat edit
Stéphane Chazelas

1
The {BASH_XTRACEFD}>trick bekerja di bash4.1 atau lambat juga.
chepner

@ chepner, ya fitur ditambahkan ke zsh, ksh93 dan bash pada saat yang sama atas saran dari pengembang zsh. Tapi, di sini tidak berfungsi untuk ksh93atau bashbahwa variabel tidak dilewatkan di lingkungan perintah (bandingkan <shell> -c 'export fd; printenv fd {fd}> /dev/null'dalam zsh, bashdan ksh93). Anda dapat membuatnya bekerja dalam ksh93/ bashdengan melakukannya dalam dua langkah atau mungkin menggunakan eval, tetapi untuk bash, itu akan memiliki efek samping jika opsi xtrace aktif.
Stéphane Chazelas

5

Karena itu skrip, Anda dapat membuat salinannya, dan mengeditnya.

Selain itu, memfilter output akan tampak sederhana, Anda dapat secara eksplisit mengatur PS4sesuatu yang lebih tidak biasa daripada satu plus, untuk membuat pemfilteran lebih mudah:

PS4="%%%%" bash script.sh 2>&1 | grep -ve '^%%%%'

(tentu saja itu akan meruntuhkan stdout dan stdin, tetapi hanya memipkan stderr di Bash menjadi sedikit berbulu, jadi saya akan mengabaikannya)


1
Piping hanya stderr mudah: PS4="%%%%" bash script.sh 2> >(grep -ve '^%%%%').
Patrick

4
@ Patrick, melakukan hal itu di bashmemiliki masalah karena grepdijalankan secara tidak serempak (bash tidak menunggu, jadi itu bisa (dan sering kali) menghasilkan sesuatu setelah perintah berikutnya dalam skrip dimulai).
Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.