úterý 13. května 2014

hh a hf - aneb jak si zpříjemnit dolování příkazů z historie Bashe

Před časem jsem objevil konzolovou utilitu hstr, která umí vyhledávat v souboru s historií Bashe a vkládat nálezy zpět do řádku shellu, případně je rovnou i spouštět. Je to pohodlnější náhrada reverzního vyhledávání přes Ctrl+R, které má Bash implementováno. Tehdy jsem to tu zmínil v komentářích a arrange prohlásil, že je to fajn, ale že mu dané vyhledávání nestačí a že ho vylepší. A tak se také stalo. Tak se na oba výtvory trochu podíváme. A nebudu vás napínat - arrange to má lepší! ...




hstr - https://github.com/dvorka/hstr

Projekt Tomáše Dvořáka je na GitHubu cca pět měsíců a poslední změny autor dělal před pár dny, mrtvé to tedy není, aktualizace probíhají a promítají se v ppa, ze kterého lze aplikaci pohodlně nainstalovat.

Výchozí zobrazení vypadá vždy takto  (šedá na černé), nastavením proměnné prostředí HH_CONFIG na hicolor může být  vybraný řádek zvýrazněn zeleně


Instalace do Ubuntu 12.04 a novějšího:

sudo add-apt-repository ppa:ultradvorka/ppa
sudo apt-get update
sudo apt-get install hh

hstr se spouští příkazem hh přímo v terminálu a po spuštění zabere celou plochu obrazovky, či okna, ve kterém terminál běží. První řádek je vstupní, kam píšete hledaný vzor, pod ním jsou dva řádky s nápovědou k ovládání a informacemi a zbytek okna jsou řádky s výsledky hledání.

Ve vstupním řádku je možné mazat poslední znaky, zkratkou Ctrl+U smazat celý vstup, ale není možné se v něm pohybovat kurzorovými klávesami, ty program ukončí a do řádku vašeho terminálu vloží aktuálně vybraný řádek z historie, nebo to, co jste napsali, pokud jste žádný z výsledků neoznačili. Chování šipek vlevo/vpravo je nedokumentované, oficiálně je k tomuto účelu vyhrazena klávesa Tab. To, že se automaticky neoznačí první výsledek hledání je ale jednoznačně špatně, nikdy se tak nevyhnete nutnosti stisknout šipku dolů, abyste mohli nalezený příkaz použít. Klávesou Enter se označený příkaz okamžitě spustí a hstr můžete opustit pomocí Ctrl+G stejně jako reverzní vyhledávání Bashe, nebo klávesou Esc.

Výsledky můžete procházet šipkami nahoru a dolů, ale máte jich vždy k dispozici pouze tolik, kolik se jich vejde na konkrétní terminál, z posledního řádku se dostanete opět na ten první. Pokud si tedy například pamatujete pouze část příkazu, která se opakuje v historii často, ale hledaný výsledek se nevejde na aktuální terminál, musíte si vzpomenout na něco dalšího, nebo použít jiné nástroje. Další možností jak dostat další výsledky, je zvětšit okno terminálu, další řádky se automaticky doplní.

hstr umí vyhledávat přesné vzory (výchozí nastavení), nebo regulární výrazy. Mezi těmito režimy se přepíná zkratkou Ctrl+E. Pro oba režimy funguje volba case insensitive, kterou můžete ovládat zkratkou Ctrl+T.

Ve výchozím stavu řadí hstr výsledky nikoliv podle pořadí v historii, ale podle podle "rankingu", jak přesně algoritmus funguje jsem nezkoumal. Každopádně dávám přednost klasickému řazení od posledního, které můžete přepnout zkratkou Ctrl+/ (režim history), dalším stiskem přepnete na režim favorites, tedy seznam oblíbených, ty si sem můžete z výsledků ukládat pomocí Ctrl+F. Zkratka Ctrl+/ mi ovšem na české klávesnici koliduje s funkcí zoom gnome-terminalu, takže je tu nepoužitelná. V xterm mi pro změnu nefunguje vůbec. Původně jsem si tohoto nedostatku nevšiml, v terminálu Terra, který používám, se tento problém nevyskytuje a v konzole (Ctrl+Alt-Fx) také ne.

Pomocí klávesy Delete také můžete jednotlivé řádky z historie mazat, ovšem tato funkce nebudí příliš důvěry tím, že po stisku klávesy řádek nezmizí, ale přepíše se nějakým nesmyslem mimo rozsah použité znakové sady. Když jsem ale pro jistotu monitoroval editovaný soubor, bylo smazáno, co mělo. A dělá to pouze v režimu history, v ranking ne. A to jsem ještě nezmínil neschopnost zpracovat většinu českých znaků s diakritikou..

K dispozici je i pár přepínačů (viz hh --help), například s přepínačem -n můžete hh použít jako filtr, který vyhledá řetězec v ~/.bash_history a odpovídající řádky vypíše rovnou na stdout, nepoužije tedy interaktivní režim. Přes přepínače ale nelze přenastavit výchozí chování rozhraní, na to musíte přes nastavení proměnné HH_CONFIG před spuštěním programu, což umožňuje globální konfiguraci přes bashrc. Proměnná může obsahovat libovolnou kombinaci následujících možností, oddělených čárkami:

hicolor - obarví zvýraznění aktuálního řádku na zeleno
rawhistory - výchozí řazení historie bude klasické od nejnovějšího po nejstarší
favorites - výchozí zobrazení budou oblíbené příkazy
casesensitive - výchozí vyhledávání bude citlivé na malá/velká písmena
warning - nějaké debugovací informace do terminálu


Přepínačem --show-configuration si můžete nechat vypsat doporučené nastavení historie Bashe, které si můžete přidat do vašeho ~/.bashrc. Především se nastaví na řádově větší číslo maximální počet řádků historie, aby bylo v čem hledat. Následující příkaz zmíněné nastavení rovnou do bashrc přidá, takže tak bude nastaven každý další Bashový shell, který otevřete.

hh --show-configuration >> ~/.bashrc


hf - http://sourceforge.net/projects/h-f/

arrange tedy hstr forknul a nakonec ho přepsal poměrně výrazně. Zahodil režimy ranking a favorites, které mi vůbec nechybí, zahodil i mazání, které mi naopak chybí. Pro zobrazení použil aktuální barvy terminálu, ne své vlastní, jako hstr (který je vždy šedý na černém), jen ve výsledcích obarvil červeně části odpovídající hledanému vzoru, stejně jako je v Ubuntu nastaven třeba grep. A samozřejmě doplnil vyhledávání. Základní režim vyhledávání byl rozšířen o výsledky, které neobsahují přesně zadaný řetězec, ale jeho písmena v daném pořadí kdekoliv na řádku. Najde tedy i prdel, když napíšete prl. Teď koukám, že mně to našlo prdelní vačici.. Tak se dá pohodlně hledat i více řetězců, které nejsou hned za sebou. A režim vyhledávání regulárních výrazů je k dispozici také.


Označený řádek má bídný kontrast, pokud máte terminál se světlým písmem. Tady by to chtělo natvrdo přebarvit písmo tak, aby byl kontrast zajištěn vždy.

Dalším vylepšením je možnost hf přesměrovat na libovolný textový soubor přepínačem -f, není tedy omezen pouze na ~/.bash_history. Dalšími přepínači můžete nastavit rozsah regulárních výrazů a změnit výchozí chování programu (viz hf --help) podle potřeb, stačí si pak udělat alias hf (nebo jakýkoli jiný) s rovnou s přepínači, aby to tak bylo vždy. Já jsem si například hf přejmenoval na h a na hf si dal hf -f.

Instalace hf zatím zahrnuje kompilaci, ale je to triviální záležitost, dá se to celé, včetně instalace, zajistit i jedním řádkem:

wget http://sourceforge.net/p/h-f/code/ci/master/tree/hf.c && sudo apt-get install libncursesw5-dev && gcc -O2 -Wall -o hf hf.c -lncursesw && sudo mv hf /usr/local/bin/hf && sudo chown root:root /usr/local/bin/hf

Nastavení hh/hf na klávesovou zkratku Bashe

Když už jsem zmínil, že uvedené nástroje mohou nahradit reverzní vyhledávání na Ctrl+R, tak proč jimi nepřerazit i tuto klávesovou zkratku? Pro tento účel je Bash vybaven klíčovým slovem bind, následující řádek si můžete také přidat do ~/.bashrc:

bind '"\C-R": "\C-A hh \n"'

nebo
bind '"\C-R": \C-A hf \n'

podle toho, kterou z aplikací si vyberete.

Klávesovou zkratku si můžete vybrat i jinou, jen pozor na to, abyste si nepřepsali nějakou výchozí, která by vám pak mohla chybět.

Závěr

hstr byl bez diskuze dobrý nápad (tedy jinou podobnou aplikaci jsem předtím nepotkal), ale zaměřuje se na věci, které u mě nemají prioritu a základu poměrně dost chybí. Krom méně pohodlného vyhledávání, především vůbec nepodporuje UTF-8, takže neumí pracovat s českými znaky, což je vzhledem k českému autorovi překvapivé.

arrange z toho udělal něco, co se dá skutečně používat. Je to dva měsíce, co prohlásil, že to vylepší, před měsícem mi poslal hotovou věc a od té doby na to "nesáhl" (nebyla zatím aktualizace). A já na tom zatím nenašel jinou chybu, než že to neumí něco, co arrange umět nechtěl. Až vrátí to mazání řádků, případně doplní možnost procházet výsledky za hranici jedné stránky, bude to dokonalé.

4 komentáře:

  1. Ahoj,

    včera jsem si četl tvůj příspěvek na téma ShutDown GTimer, a říkal jsem si: Proč to ten chlap dělá? Co blbne? Taková utilitka na vypínání počítače, a co kolem toho nadělá, co je to práce a ztraceného času! Nějak jsem ale neměl srdce ti to tam napsat. Přepl jsem virtuální plochu, spustil Geany, a zjistil, že v něm mám otevřeno asi 15 záložek s různými programy, které si dělám, abych si "ušetřil" čas - zálohování, web server, zpracování mailů, stahování podcastů, rss server,... Nějak nestíhám. A vždycky mě zaujme nějaký problém nebo bug a odběhnu zase jinam. Co blbnu? Nevím! Je to zabité...

    Takže jinak - ty prostě stíháš psát vlastní programy a ještě recenzovat cizí a psát blogy. Hats off!

    Pár poznámek k tvým poznámkám:

    - funkce mazání je příliš riskantní operace - je relativně jednoduché a bezpečné soubor načíst, nebo připsat data na konec, ale přepisovat prostředek zavání průserem - každá malá chyba v programu může zničit celou historii, co když mažeš zároveň ve 2 otevřených oknech apod. Takže pokud nedojde k pohrůžkám násilí - WONT FIX :(

    - "bind -x" mě nenapadlo, je to lepší varianta než samotné "bind". To má ale také své výhody: pokud je na bash řádku už nějaký text, a dám Ctrl+r, nezamíchá se vybraný příkaz do starého textu. Také není pravda, že se příkaz "hh" ukládá do historie: je tam schválně na začátku mezera (" hh"), což říká bashi, aby příkaz do historie neukládal (což lze nastavit, a Ubuntu to tak má v defaultu co vím)

    - není pravda, že bych na hf "nešáhl", jen jsem si nezvykl na git (používám samozřejmě vlastní verzovací systém :), takže dám vždycky až commit výsledku. Momentálně pracuju na deduplikaci řádků, neomezeném procházení příkazů, zlepšení funkce u obsáhlých souborů atd. Podobně jako ty mám rád, když je výsledek co nejlepší, a tak to chvíli trvá...

    - s tou barvou a kontrastem vybraného řádku máš pravdu, není to dobré. Je to tím, že jsem chtěl zachovat původní barvy terminálu, a sám používám černé písmo na bílém transparentním pozadí, a ten nevýrazný kontrast mi vyhovuje. Zatím je možné to změnit přímo v kódu (ř. 1048), časem to třeba dopracuju, náměty vítány.

    Programování zdar! a ještě jednou dík.

    arrange

    OdpovědětSmazat
    Odpovědi
    1. K bindu - nevycházel jsem z tvých poznámek na sf (tohle jsem tam minul), ale z těch Tomášových, ten tam tu mezeru nemá. Sám jsem si ji tam automaticky dal, ale pak jsem se včera začal hrabat v manuálu a úplně zapomněl, že mi to s -x nevloží již napsané, nechal jsem to málo uležet. Raději jsem to přepsal zpět, s -x asi již napsané nenačtu.

      Nesáhl, tím jsem myslel veřejně, jinak jsem věštit nechtěl.

      Ten SGTimer je taková moje úchylka a pískoviště, sám pro něj ani moc nemám využití. Je v tom i odpor ke všem těm hnusným polofunkčním bastlům, které máme v oficiálních repozitářích, obecně. A právě proto, že tomu nevěnuju moc času a sednu k tomu na chvíli maximálně jednou za půl roku, táhne se to jako smrad, který pak vypustím ve zbytečném článku na blogu.

      Díky za poznámky a beru na vědomí :)

      Smazat

Zkuste prosím při komentováni používat místo volby Anonymní volbu Název/adresa URL, kde vyplníte nějakou přezdívku, adresu zadávat nemusíte. Vědět, které příspěvky jsou od jednoho člověka, je fajn. Díky.

Pokud by se vám náhodou odeslaný komentář na stránce nezobrazil, vytáhnu ho z koše hned jak si toho všimnu. I Google spam filter se občas sekne.