Bir bash betiğinde hata ayıklama nasıl yapılır? [kapalı]


159

Bir bash betiğinde hata ayıklamanın herhangi bir yolu var mı? Örneğin, "arama hattı 1", "arama hattı 2" gibi bir tür yürütme günlüğü yazdıran bir şey.



Yanıtlar:


195
sh -x script [arg1 ...]
bash -x script [arg1 ...]

Bunlar, yürütülmekte olan şeyin izini verir. (Ayrıca cevabın alt kısmındaki 'Açıklama' bölümüne bakınız.)

Bazen, betik içindeki hata ayıklamayı kontrol etmeniz gerekir. Bu durumda, Cheeto'nun hatırlattığı gibi , şunları kullanabilirsiniz:

set -x

Bu hata ayıklamayı açar. Ardından aşağıdakilerle tekrar kapatabilirsiniz:

set +x

(Geçerli izleme durumunu $-, için geçerli bayrakları analiz ederek bulabilirsiniz x.)

Ayrıca, mermiler genellikle -n'yürütme yok' ve -v'ayrıntılı' mod için ' ' seçenekleri sunar ; Kabuğun betiğinizi çalıştırabileceğini düşünüp düşünmediğini görmek için bunları birlikte kullanabilirsiniz - bir yerlerde dengesiz bir teklifiniz varsa bazen yararlıdır.


Bash'teki ' -x' seçeneğinin diğer kabuklardan farklı olduğu konusunda tartışmalar var (yorumlara bakın). Bash Kılavuzu diyor ki:

  • -x

    Genişletildikten ve yürütülmeden önce basit komutların, forkomutların, casekomutların, selectkomutların ve aritmetik forkomutların ve bunların bağımsız değişkenlerinin veya ilişkili sözcük listelerinin bir izini yazdırın . Değeri PS4değişken genişletilir ve elde edilen değer komut ve genişletilmiş bağımsız değişkenler önce basılır.

Bu kadar çok farklı davranışlar göstermiyor gibi görünüyor. -xKılavuzda ' ' ile ilgili başka referans görmüyorum . Başlangıç ​​dizisindeki farklılıkları tanımlamaz.

Açıklama : Tipik bir Linux kutusu gibi ' /bin/sh' için bir sembolik bağlantı olan ' /bin/bash' sistemlerde (veya Bash yürütülebilir dosyasının bulunduğu her yerde), iki komut satırı komut dosyasını yürütme izlemesiyle çalıştırmanın eşdeğer etkisini elde eder. Diğer sistemlerde (örneğin, Solaris ve Linux'un bazı daha modern varyantları) /bin/shBash değildir ve iki komut satırı (biraz) farklı sonuçlar verir. En önemlisi, ' /bin/sh' Bash'teki hiç tanımadığı yapılar tarafından karıştırılacaktı. (Solaris'te /bin/shBourne kabuğudur; modern Linux'ta bazen Dash - daha küçük, daha kesin olarak POSIX'e özgü bir kabuk.) Bu adla çağrıldığında 'shebang' hattı (' #!/bin/bash' vs '#!/bin/sh'

Bash kılavuzunda, Bash POSIX modunda , bu cevabın uzun süredir devam eden ancak hatalı bir versiyonunun aksine (aşağıdaki yorumlara da bakınız), 'Bash as invoke sh' ve 'Bash as invoke' arasındaki fark ayrıntılı olarak açıklanmaktadır. bash'.

(Bash) kabuk betiğinin hatalarını ayıklarken, -xseçenekle birlikte shebang satırında adlandırılan kabuğu kullanmak mantıklı ve akılcı olacaktır . Aksi takdirde, komut dosyasını çalıştırırken hata ayıklama sırasında farklı davranışlar elde edebilirsiniz (?).


1
Bir bashsenaryo belirledi. Ve bir bash betiği çalıştırmak sh -xtamamen farklı davranmasına neden olur! Lütfen cevabınızı güncelleyin.
lhunath

1
@lhunath: 'sh -x' (veya 'bash -x') bir komut dosyasının hangi şekilde tamamen farklı davranmasını sağlar? Açıkçası, izleme bilgisini stderr'e çıkarır; bu bir cevap (benim cevabımda belirtilmese de). Peki başka ne var? Linux ve MacOS X'te 'bash' kelimesini 'sh' olarak kullanıyorum ve ciddi bir sorun fark etmedim.
Jonathan Leffler

6
Başlangıçta ve çalışma zamanında farklılıklar vardır. Bash dağıtımında tamamen belgelenmiştir.
TheBonsai

4
İşte bash dokümanı için bir bağlantı: gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files 'Bash sh adıyla çağrılırsa, sh'nin tarihsel sürümlerinin başlangıç ​​davranışını taklit etmeye çalışır. Mümkün olduğunca yakından, posix standardına da
uyurken

6
Ve PS4 istemini aşağıdaki gibi daha yararlı bilgiler vermek için kullanın:export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
estani

28

Senaryomda hata ayıklamak için aşağıdaki yöntemleri kullandım.

set -eherhangi bir harici program sıfırdan farklı bir çıkış durumu döndürürse komut dosyasını hemen durdurur. Komut dosyanız tüm hata durumlarını ele almaya çalışırsa ve bunu yapamamanız durumunda yararlıdır.

set -x yukarıda zikredilmiştir ve tüm hata ayıklama yöntemlerinden en faydalı olanıdır.

set -n betiğinizi sözdizimi hataları için kontrol etmek istiyorsanız da yararlı olabilir.

straceneler olduğunu görmek için de yararlıdır. Özellikle senaryoyu kendiniz yazmadıysanız yararlıdır.


1
Bir komut dosyasını izlemek (yani komut dosyasını yürüten bir kabuğu izlemek) garip bir kabuk hata ayıklama yöntemidir (ancak sınırlı sayıda sorun için işe yarayabilir).
TheBonsai

1
Tuhaf ve çok ayrıntılı olduğunu itiraf ediyorum, ancak strace çıktısını birkaç sistemle sınırlarsanız, yararlı olur.

1
Not strace -fAyrıca komut dosyası tarafından başlatılan süreçlerde hataları bulmak istiyorsanız gereklidir. (bu onu çok daha ayrıntılı hale getirir, ancak ilgilendiğiniz sistem çağrılarıyla sınırlarsanız yine de yararlıdır).
Random832


12

Bu cevap geçerli ve yararlı: https://stackoverflow.com/a/951352

Ancak, "standart" kod hata ayıklama yöntemlerinin verimsiz, sezgisel ve kullanımı zor olduğunu düşünüyorum. Her şeyi parmaklarınızın ucuna getiren ve işi kolay problemler (ve zor problemler için) için bir esinti yapan sofistike GUI hata ayıklayıcılarına alışkın olanlar için, bu çözümler çok tatmin edici değildir.

Yaptığım şey DDD ve bashdb'nin bir kombinasyonunu kullanmak. Birincisi ikincisini yürütür ve ikincisi komut dosyanızı yürütür. Bu, bağlamı kafanızda tutmak veya kaynağı yeniden listelemeye devam etmek için sürekli zihinsel çaba sarf etmeden bağlamda kod içinde adım atma ve değişkenleri, yığını vb. Görüntüleme yeteneğine sahip çok pencereli bir kullanıcı arayüzü sağlar.

Burada ayarlama konusunda rehberlik vardır: http://ubuntuforums.org/showthread.php?t=660223


Cevabınız için ddd'yi yeni keşfettim. Ubuntu 12.04.3'te (64bit), apt-sources sürümü çalışmaz. Benim bash betiğimi hata ayıklamaya başlamak için derleme ve kaynaktan yüklemek zorunda kaldı. Buradaki talimatlar - askubuntu.com/questions/156906/… yardımcı oldu.
chronodekar

Evet, bu bir problem. Ben bunu herhangi bir komut dosyası ile bir süre geri çözüldü - 'dddbash' yüklemeleri / DDD kurar onun yanlış ise eski sürüm kaldırır, vb bashdb, yükler (Cevap şimdi bu bilgi ile düzenlendi)
Stabledog


10

Shellcheck yardımcı programını buldum ve bazı insanlar ilginç bulabilirler https://github.com/koalaman/shellcheck

Küçük bir örnek:

$ cat test.sh 
ARRAY=("hello there" world)

for x in $ARRAY; do
  echo $x
done

$ shellcheck test.sh 

In test.sh line 3:
for x in $ARRAY; do
         ^-- SC2128: Expanding an array without an index only gives the first element.

hatayı düzeltin, önce deneyin ...

$ cat test.sh       
ARRAY=("hello there" world)

for x in ${ARRAY[@]}; do
  echo $x
done

$ shellcheck test.sh

In test.sh line 3:
for x in ${ARRAY[@]}; do
         ^-- SC2068: Double quote array expansions, otherwise they're like $* and break on spaces.

Tekrar deneyelim...

$ cat test.sh 
ARRAY=("hello there" world)

for x in "${ARRAY[@]}"; do
  echo $x
done

$ shellcheck test.sh

şimdi bul!

Bu sadece küçük bir örnek.



Neyse ki araç, geri kalan hatayı da bulduğu noktaya geldi.
Üçlü

3

VSCode'u yükleyin , sonra bash hata ayıklama uzantısını ekleyin ve görsel modda hata ayıklamaya hazırsınız. bkz Burada eylem.

resim açıklamasını buraya girin


3

Eklentileri kabuklu ve basheclipse ile kullanın.

https://sourceforge.net/projects/shelled/?source=directory https://sourceforge.net/projects/basheclipse/?source=directory

Kabuklu için: Zip dosyasını indirin ve yardım yoluyla eclipse'a aktarın -> yeni yazılım yükleyin: yerel arşiv Bashliplip için: Kavanozları eclipse'nin dropins dizinine kopyalayın

Https://sourceforge.net/projects/basheclipse/files/?source=navbar sağlayan adımları izleyin

resim açıklamasını buraya girin

Http://dietrichschroff.blogspot.de/2017/07/bash-enabling-eclipse-for-bash.html adresinde birçok ekran görüntüsü içeren bir eğitici yazdım.


2
Bu, yalnızca bağlantıya yönelik sınırlayıcı bir yanıttır (ayrıca buraya bakın ). Yanıtınızı, mümkün olduğunca çok bilgi içerecek şekilde, en azından önerdiğiniz şeyi gerçekleştirmek için gereken minimum bilgiyi içerecek şekilde genişletmeniz ve bağlantıları yalnızca referans olması için kullanmanız gerekir. Temel olarak, Yığın Taşması'ndaki (ve tüm Yığın Değişimi) yayınlar bağımsız olmalıdır. Bu, okuyucunun talimatlar için site dışına çıkmasına gerek kalmayacak şekilde cevabınızda yeterli bilgi bulunması gerektiği anlamına gelir . Şu anda, bu cevap için durum böyle değil.
Makyen

gerçek hata ayıklamanın mümkün olduğunu gösteren birçok kişiye baktıktan sonra bulduğum ilk cevap bu. Standart cevaplar "set + x", bağımsız bir cevapla mükemmel şekilde eşleşir, ancak gerçek hata ayıklama ile ilgili gerçek soruları neredeyse kasıtlı olarak göz ardı eder. Bu cevabı alkışladım 👏
simbo1905

2

Bir Bash hata ayıklayıcısı oluşturdum. Sadece bir deneyin. Umarım https://sourceforge.net/projects/bashdebugingbash yardımcı olur


BDB şu anda İngilizce ve İspanyolca dillerinde desteklenmektedir. Dili değiştirmek için / etc / default / bdb
abadjm

ekran görüntüsü ilginç görünüyor ama ben "bdb.sh: line 32: bdbSTR [1]: sınırsız değişken" çalıştırmak yapamadı; btw, kod üzerinde yaptığımız her adımda tüm ayarlanmış değişkenlerin geçerli değerlerini gösterecek mi?
Kova Gücü

2

set + x = @ECHO OFF, -x = @ECHO ON olarak ayarlayın.


-xvStandart Shebang'a aşağıdaki gibi seçenek ekleyebilirsiniz :

#!/bin/bash -xv  

-x: Komutları ve bağımsız değişkenlerini yürütüldükleri sırada görüntüler.
-v: Kabuk giriş satırlarını okundukları gibi görüntüler.


ltracebenzeri başka bir Linux Yardımcı Programıdır strace. Ancak, ltraceyürütülebilir veya çalışan bir işlemde çağrılan tüm kütüphane çağrılarını listeler. Adının kendisi kütüphane çağrısı izlemesinden gelir. Örneğin:

ltrace ./executable <parameters>  
ltrace -p <PID>  

Kaynak



1

Hata ayıklamak için bazı hileler Kodlar:

kullanma set -[nvx]

Ek olarak

set -x

ve

set +x

dökümü durdurmak için.

Daha set -vaz gelişmiş çıktı kadar küçük dökümü hakkında konuşmak istiyorum .

bash <<<$'set -x\nfor i in {0..9};do\n\techo $i\n\tdone\nset +x' 2>&1 >/dev/null|wc -l
21

for arg in x v n nx nv nvx;do echo "- opts: $arg"
    bash 2> >(wc -l|sed s/^/stderr:/) > >(wc -l|sed s/^/stdout:/) <<eof
        set -$arg
        for i in {0..9};do
            echo $i
          done
        set +$arg
        echo Done.
eof
    sleep .02
  done
- opts: x
stdout:11
stderr:21
- opts: v
stdout:11
stderr:4
- opts: n
stdout:0
stderr:0
- opts: nx
stdout:0
stderr:0
- opts: nv
stdout:0
stderr:5
- opts: nvx
stdout:0
stderr:5

Değişkenleri dökümü veya anında izleme

Bazı değişkenleri test etmek için bazen şunu kullanıyorum:

bash <(sed '18ideclare >&2 -p var1 var2' myscript.sh) args

Eklemek için:

declare >&2 -p var1 var2

satır 18'de ve ortaya çıkan komut dosyasını ( argümanlarla ) çalıştırmak zorunda kalmadan, bunları düzenlemek zorunda kalmadan.

tabii ki, bu eklemek için kullanılabilir set [+-][nvx]:

bash <(sed '18s/$/\ndeclare -p v1 v2 >\&2/;22s/^/set -x\n/;26s/^/set +x\n/' myscript) args

declare -p v1 v2 >&2satır 18'den sonra, set -xsatır 22'den set +xönce ve satır 26'dan önce eklenecektir .

küçük örnek:

bash <(sed '2,3s/$/\ndeclare -p LINENO i v2 >\&2/;5s/^/set -x\n/;7s/^/set +x\n/' <(
        seq -f 'echo $@, $((i=%g))' 1 8)) arg1 arg2
arg1 arg2, 1
arg1 arg2, 2
declare -i LINENO="3"
declare -- i="2"
/dev/fd/63: line 3: declare: v2: not found
arg1 arg2, 3
declare -i LINENO="5"
declare -- i="3"
/dev/fd/63: line 5: declare: v2: not found
arg1 arg2, 4
+ echo arg1 arg2, 5
arg1 arg2, 5
+ echo arg1 arg2, 6
arg1 arg2, 6
+ set +x
arg1 arg2, 7
arg1 arg2, 8

Not: Dikkat , anında yapılan değişikliklerden $LINENOetkilenecektir !

(Çalıştırılmadan ortaya çıkan komut dosyasını görmek için, bırakın bash <(ve bırakın ) arg1 arg2)

Adım adım yürütme süresi

Bash betiklerini nasıl profili oluşturacağımla ilgili cevabıma bir göz atın


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.