BASH geçmişinde yalnızca başarılı komutları koru


20

Bazen bir komutun sözdizimini yanlış anlıyorum:

# mysql -d test
mysql: unknown option '-d'
# echo $?
2

Tekrar deniyorum ve doğru anladım:

# mysql --database test
Welcome to the MySQL monitor.
mysql >
...

Hata kodu 0'dan farklı olan ilk komutun geçmişe girmesini nasıl önleyebilirim?

Yanıtlar:


20

Bunu gerçekten istediğini sanmıyorum. Her zamanki iş akışım şöyle:

  • Bir komut yazın
  • Çalıştır
  • Başarısız olduğuna dikkat edin
  • YUKARI tuşuna basın
  • Komutu düzenleyin
  • Tekrar çalıştır

Şimdi, başarısız komut tarihe kaydedilmemişse, düzeltmek ve tekrar çalıştırmak için kolayca geri alamadım.


3
Sanırım daha iyi bir tasarım bir oturum geçmişi ve kalıcı bir tarih olurdu. Teşekkürler!
Adam Matan

Terminalden çıktığınızda geçmiş kaydedilir. Böylece , bu terminal oturumunda yazdığınız komutlara geri dönebilirsiniz, ancak aslında terminalden çıkarken bash geçmişine kaydedilir.
To Do

11

Bunu yapmak için düşünebildiğim tek yolu kullanmak olacaktır history -diçinde $PROMPT_COMMAND. Bu veya herhangi bir yaklaşımla ilgili sorun, bir komutun bir hatayla çıkıp çıkmadığını veya sıfır olmayan bir çıkış koduyla başarıyla tamamlandığını anlamanın imkansız olmasıdır.

$ grep non_existent_string from_file_that_exists
$ echo $?
1

4

Düzeltmek için son yanlış yorum yapmak iyidir, ancak bundan kısa bir süre sonra, çöp karıştırabilir.

Benim yaklaşımım iki aşamalı: komutları, başarısız olduklarında saklayın ve bir süre sonra kaldırın.

Yaptıklarında başarısız olan komutları saklayın:

error_handler() {
    FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}

trap error_handler ERR

trap command signalscommandbiri signals"yükseltildiğinde" yürütür .

$(command), yürütür commandve çıktısını yakalar.

Komut başarısız olduğunda, bu kod snippet'i tarihe kaydedilen son komutun geçmiş sayısını yakalar ve ileride silinmek üzere değişkente saklar.

Basit, ancak yanlış çalışıyor HISTCONTROLve HISTIGNORE- değişkenlerden biri nedeniyle komut geçmişe kaydedilmediğinde, tarihe kaydedilen son komutun geçmiş numarası önceki komutun biridir; dolayısıyla, yanlış komut geçmişe kaydedilmezse, önceki komut silinir.

Bu durumda doğru çalışan biraz daha karmaşık sürüm:

debug_handler() {
    LAST_COMMAND=$BASH_COMMAND;
}

error_handler() {
    local LAST_HISTORY_ENTRY=$(history | tail -1l)

    # if last command is in history (HISTCONTROL, HISTIGNORE)...
    if [ "$LAST_COMMAND" == "$(cut -d ' ' -f 2- <<< $LAST_HISTORY_ENTRY)" ]
    then
        # ...prepend it's history number into FAILED_COMMANDS,
        # marking the command for deletion.
        FAILED_COMMANDS="$(cut -d ' ' -f 1 <<< $LAST_HISTORY_ENTRY) $FAILED_COMMANDS"
    fi
}

trap error_handler ERR
trap debug_handler DEBUG

Bir süre sonra depolanan komutları kaldırın:

exit_handler() {
    for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
    do
        history -d $i
    done
    FAILED_COMMANDS=
}

trap exit_handler EXIT

Açıklama:

Bash'ten çıkarken, her benzersiz geçmiş numarası için karşılık gelen geçmiş girişini kaldırın,
daha sonra FAILED_COMMANDSsilinmiş komutlardan geçmiş numaralarını devralan komutları kaldırmamak için temizleyin .

Eminseniz o FAILED_COMMANDSkopyalardan ücretsiz olacak yapabilirsiniz bitti basit yinelerler
(yani. Yazma for i in $FAILED_COMMANDS). Ancak, bunu (bu durumda her zaman olduğu) en büyük en küçüğüne sıralanır edilecek bekliyorsanız, yerini uniqile sort -rnu.

İçindeki geçmiş sayıları FAILED_COMMANDSbenzersiz olmalı ve en büyüğünden en küçüğe sıralanmalıdır, çünkü girişi sildiğinizde, sonraki komutların numaraları kaydırılır - yani. yayınladığınızda history -d 23. giriş 2. olur, 4. giriş 3. olur vb.

Bu nedenle, bu kodu kullanırken, depolanan en büyük sayıya eşit veya daha küçük olan history -d <n>
yerlerinFAILED_COMMANDS manuel olarak arayamaz
ve kodun düzgün çalışmasını bekleyemezsiniz.

Muhtemelen kanca iyi bir fikirdir exit_handlerde EXIT, ama aynı zamanda her zaman daha erken diyebiliriz.

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.