Bash set + x tanpa dicetak

95

Adakah yang tahu jika kami dapat mengatakan set +xdalam bash tanpa dicetak:

set -x
command
set +x

jejak

+ command
+ set +x

tetapi seharusnya hanya dicetak

+ command

Bash adalah Versi 4.1.10 (4). Ini mengganggu saya untuk beberapa waktu sekarang - output berantakan dengan set +xbaris yang tidak berguna , membuat fasilitas pelacakan tidak berguna seperti yang seharusnya.

Andreas Spindler
sumber
Ini tidak menjawab pertanyaan Anda, tetapi ketika Anda menjalankan skrip Anda mengapa tidak:script.sh 2>&1 | grep -v 'set +x'
cdarke

Jawaban:

148

Saya memiliki masalah yang sama, dan saya dapat menemukan solusi yang tidak menggunakan subkulit:

set -x
command
{ set +x; } 2>/dev/null
McJoey
sumber
10
Jawaban yang bagus, hanya catatan: tanpa titik koma setelah perintah ini tidak akan berfungsi; dan dengan titik koma tetapi tanpa spasi pada tanda kurung kurawal, kesalahan sintaksis akan dimunculkan.
sdaau
9
Ini nol status keluar.
Garth Kidd
8
Status Keluar @GarthKidd dinolkan dengan setiap perintah yang berhasil. set +xadalah perintah yang sangat sukses
Daniel Alder
4
Dalam kasus di mana Anda perlu status keluar dari command, variasi ini adalah solusi: { STATUS=$?; set +x; } 2>/dev/null. Kemudian periksa $STATUSdi baris berikutnya di waktu luang Anda.
Greg Harga
5
Secara terpisah, inilah versi golfed sedikit lebih: { set +x; } 2>&-. Itu menutup fd 2 secara langsung daripada membuatnya mengarah ke / dev / null. Beberapa program tidak menanganinya dengan baik ketika mereka mencoba mencetak ke stderr, itulah sebabnya / dev / null secara umum adalah gaya yang bagus; tapi set -xpelacakan shell menanganinya dengan baik, jadi ini bekerja dengan sempurna di sini, dan itu membuat mantera ini sedikit lebih pendek.
Greg Harga
43

Anda dapat menggunakan subkulit. Setelah keluar dari subkulit, setelan ke xakan hilang:

( set -x ; command )
choroba
sumber
Terima kasih ... poin yang bagus. Sebenarnya saya mengetahui "trik sub-shell". Saya berharap bisa lebih mudah dari itu. Ini melibatkan perubahan substansial dalam kode, membuat kode lebih kompleks dan kurang dapat dibaca. IMHO yang akan lebih buruk daripada hidup dengan set + x lines ...
Andreas Spindler
Saya tidak melihat bagaimana ( set -x \n command \n )bisa lebih buruk dari set -x \n command \n set +x.
chepner
3
@chepner: Anda tidak dapat menyetel variabel.
choroba
2
... dan Anda tidak bisa cd: itu tidak mengubah direktori saat ini di shell induk.
Andreas Spindler
Maaf, saya tidak yakin apa yang saya pikirkan tentang keberatan Anda yang sebenarnya. Sudah seminggu yang panjang ...
Chepner
8

Saya meretas solusi untuk ini baru-baru ini ketika saya merasa kesal dengannya:

shopt -s expand_aliases
_xtrace() {
    case $1 in
        on) set -x ;;
        off) set +x ;;
    esac
}
alias xtrace='{ _xtrace $(cat); } 2>/dev/null <<<'

Ini memungkinkan Anda untuk mengaktifkan dan menonaktifkan xtrace seperti berikut ini, di mana saya mencatat bagaimana argumen ditetapkan ke variabel:

xtrace on
ARG1=$1
ARG2=$2
xtrace off

Dan Anda mendapatkan hasil yang terlihat seperti:

$ ./script.sh one two
+ ARG1=one
+ ARG2=two
pengguna108471
sumber
Trik cerdas (meskipun Anda tidak membutuhkan /dev/stdinbagiannya). Peringatannya adalah bahwa mengaktifkan perluasan alias dalam skrip dapat memiliki efek samping yang tidak diinginkan.
mklement0
Kamu benar. Saya telah mengedit jawaban untuk menghapus yang tidak berguna /dev/stdin. Saya tidak mengetahui adanya efek samping tertentu, karena lingkungan non-interaktif seharusnya tidak memuat file apa pun yang menentukan alias. Apa efek sampingnya?
pengguna108471
1
Itu poin yang bagus - Saya lupa bahwa alias tidak diwariskan, jadi risikonya jauh lebih kecil daripada yang saya kira (secara hipotetis, skrip Anda dapat mengambil kode pihak ketiga yang kebetulan mendefinisikan alias, tapi saya setuju itu mungkin bukan nyata- perhatian dunia). +1
mklement0
1
@AndreasSpindler Bisakah Anda menjelaskan mengapa menurut Anda teknik ini lebih cenderung membocorkan informasi yang lebih sensitif?
pengguna108471
1
... pada dasarnya karena alias dan fungsi adalah konstruksi tingkat tinggi. set +xjauh lebih sulit (jika bukan tidak mungkin) untuk berkompromi. Tetapi ini masih merupakan solusi yang baik dan lurus - mungkin yang terbaik sejauh ini.
Andreas Spindler
7

Bagaimana dengan solusi yang didasarkan pada versi @ user108471 yang disederhanakan:

shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ set +x; } 2>/dev/null'

trace_on
...stuff...
trace_off
Oliver
sumber
Bagaimana dengan ini? function () { set_plus_x='{ set +x; } 2>/dev/null' }
LexH
1

Ini adalah kombinasi dari beberapa ide yang dapat menyertakan blok kode dan mempertahankan status keluar.

#!/bin/bash
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ PREV_STATUS=$? ; set +x; } 2>/dev/null; (exit $PREV_STATUS)'

trace_on
echo hello
trace_off
echo "status: $?"

trace_on
(exit 56)
trace_off
echo "status: $?"

Saat dijalankan:

$ ./test.sh 
+ echo hello
hello
status: 0
+ exit 56
status: 56
pengguna3286792
sumber
Usaha yang bagus tapi saya pikir ()sekitar exittidak perlu. Baik. Mungkin itu yang paranoid, tetapi jika kode ini digunakan secara umum Anda memiliki vektor serangan yang baik: mendefinisikan kembali trace_ondan trace_offdan kode inject yang bertuliskan perintah dieksekusi. Jika Anda menggunakan "kegunaan" seperti itu saja, itu instruktif, tetapi jika kode digunakan dengan orang lain, Anda harus mempertimbangkan apakah manfaat dari fungsi non-standar tersebut lebih besar daripada kerugiannya. Secara pribadi saya telah menyelesaikan { set +x; } 2>/dev/nullkarena konstruksi ini umumnya dipahami dan juga tidak mengubah status keluar.
Andreas Spindler
Terima kasih. Saya telah membagikan pendekatan ini dengan kolega saya dan mereka menyukai cara ini menjaga keluaran dan kode tidak terlalu berisik. Mengenai ()sekitar exit 56; itu hanya agar saya bisa menunjukkan bahwa status keluar dari subproses dapat diakses di skrip bash; tanpa tanda kurung, itu tidak akan menjadi subproses dan skrip akan keluar pada saat itu dengan status = 65.
pengguna3286792