Betik yürütme izlemesini (set -x) komut dosyasının dışından bastır


17

Bu soruya bir cevap bulmaya çalıştım, ancak şu ana kadar hiç şansım olmadı:

Bazı diğer komut dosyalarını çalıştıran bir komut dosyası var ve bu komut dosyalarının çoğunun "set -x" var, bu da yürüttükleri her komutu yazdırır. Bundan kurtulmak istiyorum, ancak komut dosyalarından herhangi biri hata mesajını stderr'a gönderirse bilgileri saklayın.

Bu yüzden yazamıyorum ./script 2>/dev/null

Ayrıca, bu diğer komut dosyalarını düzenleme ayrıcalığım yok, bu yüzden set seçeneğini el ile değiştiremiyorum.

Stderr ayrı dosyaya her şeyi günlüğe kaydetme ve izleme komutları filtreleme hakkında düşünüyordum, ama belki daha basit bir yolu var mı?


1
./script 2>some_file
Satō Katsura

Yanıtlar:


25

İle bash4.1 ve üzeri, yapabileceğiniz

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

( basholarak çağrıldığında da çalışır sh).

Temel olarak, bashçıktıyı xtracevarsayılan 2 yerine dosya tanımlayıcı 7'ye çıkarmayı ve bu dosya tanımlayıcıya yeniden yönlendirmeyi söylüyoruz /dev/null. Fd numarası isteğe bağlıdır. Betiğinizde başka şekilde kullanılmayan 2'nin üzerinde bir fd kullanın. Bu komutu girdiğiniz kabuk bashveya ise yash, 9'un üstündeki bir sayıyı bile kullanabilirsiniz (dosya tanımlayıcı kabuk tarafından dahili olarak kullanılıyorsa sorunla karşılaşabilirsiniz).

Bu bashkomut dosyasını çağırdığınız kabuk ise zshşunları da yapabilirsiniz:

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

değişkenin otomatik olarak 9'un üzerindeki ilk boş fd atanması için.

Eski sürümleri için bash, başka bir seçenek, eğer xtraceaçıksa set -x( #! /bin/bash -xveya aksine set -o xtrace) set, aktarıldığında hiçbir şey yapmayan bir dışa aktarma işlevi olarak yeniden tanımlamak -xolacaktır (ancak komut dosyasını (veya bashçağırdığı herhangi bir komut dosyasını) bozar) setkonum parametrelerini ayarlamak için kullanılır ).

Sevmek:

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

Başka bir seçenek de, her komuttan önce gelen bir $BASH_ENVdosyaya DEBUG tuzağı eklemektir set +x.

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

Yine de set -xbir alt kabukta yapıldığında bu işe yaramaz .

@İlkkachu'nun dediği gibi, dosya sistemindeki herhangi bir klasöre yazma izniniz varsa, en azından komut dosyasının bir kopyasını oluşturabilir ve düzenleyebilirsiniz.

Komut dosyasının bir kopyasını yazabileceğiniz bir yer yoksa veya orijinal komut dosyasında her güncelleme olduğunda yeni bir kopya oluşturup düzenlemek uygun değilse, yine de yapabilirsiniz:

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

Komut dosyası ile süslü bir şey $0veya özel değişkenler $BASH_SOURCE(komut dosyasının kendisiyle ilgili dosyalara bakmak gibi) yaparsa, bu (ve kopya yaklaşımı) düzgün çalışmayabilir , bu nedenle aşağıdaki gibi bazı düzenlemeler yapmanız gerekebilir $0betiğin yoluyla değiştir ...


İlk cevabım tam olarak ihtiyacım olan şey, temiz ve zarif. Nasıl çalıştığını biraz açıklayabilir misiniz? Neden 7 numara? Diğer numaralar ne için kullanılabilir? Teşekkürler.
insan

insan, bkz. düzenleme
Stéphane Chazelas

1
{BASH_XTRACEFD}>Hile çalışır bashsonradan yanı 4.1 veya.
chepner

@ chepner, evet bu özellik zsh geliştiricisinin önerisi üzerine zsh, ksh93 ve bash'a aynı anda eklendi. Ama, işte burada için iş yapmaz ksh93veya bashdeğişken komutunun (karşılaştırma ortamında geçmedi ki <shell> -c 'export fd; printenv fd {fd}> /dev/null'içinde zsh, bashve ksh93). İki adımda veya muhtemelen kullanarak ksh93/ çalışmasını sağlayabilirsiniz , ancak xtrace seçeneği açıksa bunun yan etkileri olabilir. bashevalbash
Stéphane Chazelas

5

Onlar komut olduğuna göre, olabilir bunların kopyalarını yapmak ve düzenlemek olanlar.

Bunun dışında, çıktıyı filtrelemek basit görünecektir PS4, filtrelemeyi kolaylaştırmak için açıkça tek bir artıdan daha sıra dışı bir şeye ayarlayabilirsiniz :

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

(tabii ki stdout ve stdin'i çökertecek, ancak Bash'te sadece stderr boruları biraz kıllı oluyor, bu yüzden görmezden geleceğim)


1
Sadece Stderr Boru kolaydır: PS4="%%%%" bash script.sh 2> >(grep -ve '^%%%%').
Patrick

4
@Patrick, bunu yaparken, eşzamansız olarak çalıştırıldığı bashgibi sorunları vardır grep(bash onu beklemez, böylece komut dosyasındaki bir sonraki komut başlatıldıktan sonra çıktılar alabilir (ve çoğu zaman yapar)).
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.