Function, azaz függvény a bashrc-ben

Function, azaz függvény a bashrc-ben
Function, azaz függvény a bashrc-ben
Function? Aki már programozott egy picit ismerni ezt a fogalmat. Aki pedig nem, neki gyorsan összefoglalom: egy olyan programozási szerkezet, amiben egy névhez hozzárendelünk összetettebb programrészt, amire ezentúl a névvel tudunk hivatkozni. Így csak egyszer kell összeállítani ezt a kis programrészt és azután végtelenszer fel tudjuk használni. Most természetesen nem programozni fogunk, csak a bash shellben (pontosabban a bashrc-ban) készítünk ilyen kis programocskákat, amiket szeretnénk használni. Ezek jellemzően egyszerű megoldások, amiket többször használunk, de nem nagyon van kedvünk a sok gépeléshez. Ez egy nagyon durva leegyszerűsítése a shell-ekben megtalálható function lehetőségeknek. Általában függvényeknek fordítják, én vegyesen használom majd a két kifejezést.

Logikusan felmerül a kérdés, hogy ez olyan mint az alias, illetve s szkript? Igen, ez olyan. Legalábbis a feladatát tekintve: rövid névvel látunk el egy hosszabb parancsot, összetettebb megoldást, majd ennek a névnek a használatával mentesülünk a sok gépeléstől.

Alapok

Az alapjai egyszerűek.

  • Az általam bemutatott function a bashrc-be kerül. Ha zsh-t használsz, akkor a zshrc-be. Ha más shellt, akkor nézd meg a leírásban!
  • Mivel a bashrc-ben van, a terminál nyitásakor kerül beolvasásra, így ha zsh-ra váltasz, oda is be kell külön írni.

A szerkezete kötött, de egyszerű:


 function_name () { 
         commands 
 }

 #egyszoros megoldással:
function_name () { commands; }

 #vagy így: 
 function function_name {
         commands
 }

 # Ennek az egysoros megoldása:
  function function_name { commands; }

Bármelyik jó lesz, amit Te kényelmesnek találsz. Én praktikusság okán nem keverem őket, egy sablon alapján rakom be a saját állományomba.

  • A legtöbb esetben bármelyik összetett szerkezetet használhatod: loops, if, then, else, elif stb. szerepelhet. Itt picit alapozunk a témában.
  • Név választáskor légy körültekintő, jó ha meg is tudod jegyezni. Sem már meglévő parancs, sem pedig már meglévő szkript neve nem szerencsés!
  • A zsh és a bash nyelve nagyon hasonló, de kicsit eltérhet egyes esetekben. Nem feltétlen lesz az egyikre megírt function jó a másikban.
  • a bashrc szerkesztése és mentése után akkor lép érvénybe, ha kilépsz és vissza a terminálból, vagy új terminált nyitsz!

Alap példa a function használatára

Ez csak egy faék egyszerű példa!

Megnyitod a bashrc-det a kedvenc szövegszerkesztőddel.

Majd beírod a végére ezt a szöveget, ebben a formátumban:

function szia() {
       echo 'Hello, jó reggelt!'
}

Mentés, új terminál nyitása, vagy ki- és visszalépés a terminálba. Majd a parancssorba: szia és enter.

Már minden világos? A többi csak a fantázia kérdése. Amit meg tudsz tenni egy összetette paranccsal a terminálban, azt már function megoldással is megteheted.

Miért ezt a szerkezetet használom? Csak. Ezt szépen kiemeli a szerkesztőm, így könnyű a munka vele. Semmi különbség nincs a többi közt!

Példák minimális magyarázattal

#Jobb rm parancs
function fzf-rm() {
  if [[ "$#" -eq 0 ]]; then
    local files
    files=$(find . -maxdepth 1 -type f | fzf --multi)
    echo $files | xargs -I '{}' rm {} #Az üres helyekre is figyelő megoldás!
  else
    command rm "$@"
  fi
}

Abban a könyvtárban, ahol vagyunk kilistázza a fájlokat, majd a kijelölteket törli. Érdemes hozzá a find parancsot ismerni, illetve az fzf parancsot telepíteni. Általánosan is igaz: ha valahol összeszedünk egy parancssori megoldást a parancsokat ismerni kell, és megnézni mi az amit elvár telepített programként!

  • Megfigyelendő a megjegyzések kezelése. Itt is a sima kettős kereszt # a megjegyzés, alkalmazható sor elején, vagy akár a sorban bárhol, de ilyenkor az azt követő részt nem hajtja végre a sorban.
  • Ha fájl vagy könyvtárnevekkel is dolgozunk minden esetben gondunk legyen a szóközt is tartalmazó nevek helyes kezelésre.
  • A find és az xargs hasznos program! Az fzf-ről itt volt szó.
# Man without options will use fzf to select a page
function fzf-man() {
    MAN="/usr/bin/man"
    if [ -n "$1" ]; then
        $MAN "$@"
        return $?
    else
        $MAN -k . | fzf --reverse --preview="echo {1,2} | sed 's/ (/./' | sed -E 's/\)\s*$//' | xargs $MAN" | awk '{print $1 "." $2}' | tr -d '()' | xargs -r $MAN
        return $?
    fi
}

Gyors keresés és megjelenítés a man oldalak közt.

## Find Dirs
function fzf-cd() {
  local dir
  dir=$(find ${1:-.} -path '*/\.*' -prune \
                  -o -type d -print 2> /dev/null | fzf +m) &&
  cd "$dir"
  ls
}

A mappákat kilistázza, a fzf-el kereshetünk benne, majd a kijelöltbe ugrik és annak tartalmát kilistázza.

function extract() {
 if [ -z "$1" ]; then
    # display usage if no parameters given
    echo "Usage: extract ."
    echo "       extract  [path/file_name_2.ext] [path/file_name_3.ext]"
    return 1
 else
    for n in $@
    do
      if [ -f "$n" ] ; then
          case "${n%,}" in
            *.tar.bz2|*.tar.gz|*.tar.xz|*.tbz2|*.tgz|*.txz|*.tar) 
                         tar xvf "$n"       ;;
            *.lzma)      unlzma ./"$n"      ;;
            *.bz2)       bunzip2 ./"$n"     ;;
            *.rar)       unrar x -ad ./"$n" ;;
            *.gz)        gunzip ./"$n"      ;;
            *.zip)       unzip ./"$n"       ;;
            *.z)         uncompress ./"$n"  ;;
            *.7z|*.arj|*.cab|*.chm|*.deb|*.dmg|*.iso|*.lzh|*.msi|*.rpm|*.udf|*.wim|*.xar)
                         7z x ./"$n"        ;;
            *.xz)        unxz ./"$n"        ;;
            *.exe)       cabextract ./"$n"  ;;
            *)
                         echo "extract: '$n' - unknown archive method"
                         return 1
                         ;;
          esac
      else
          echo "'$n' - file does not exist"
          return 1
      fi
    done
fi
}

Több disztribútor alapból belerakja ezt a függvényt a bashrc-be, így ismerős lehet sokaknak. Az extract után megadjuk a kicsomagolandó fájl nevét, és már csomagolja is ki.

function mm() {
       echo 'A mentést indítom'
        mega-logout
        mega-login ezazemailcimem004@proton.me naezmegtitkos
        mega-sync /home/laci/MEGA /

}

Egy minta, hogy nem kell olyan összetettekben gondolkodni, mint az előbbiek, simán felsoroljuk a kipróbált parancsokat és azután csak használjuk. A fenti nagyon egyszerű, hibakezelés nélküli dolog, de példának jó: egyszerű és hasznos a function, azaz a függvények használata.

Függvény, alias vagy szkript?

Én aliasnak csak olyan feladatot adok meg, ami egy soros és semmi komolyabb szerkezetet nem tartalmaz. Így sokkal átláthatóbb lesz számomra az aliasokat tartalmazó rész.

Az alias és a függvény hátrány - ha nem jól kezeljük a helyzetet - a megnövekedett bashrc mérete. De mi már tudjuk, hogy a bashrc modulárissá tehető. Ha a megadott külön állományba delegáljuk ki az aliasokat és a függvényeket, majd azokat megfelelő módszerrel beimportáljuk a bashrc-be, akkor rendezetté tehetjük a dolgokat.

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

A szkript mellett szól a mobilitás. Amíg az alias és a function a bashrc (vagy egyéb állomány) része, és csakis az adott felhasználónál fut, addig a szkriptekre (bár elég kényelmetlenül) teljes elérési úttal hivatkozhatunk.

A szkript ellen szól, hogy ha nincs benne a PATH-ban, akkor nem fut, és ha elfelejtek neki futtatási jogot adni, akkor sem...

Itt is igaz: macerásnak és unalmasnak tűnik, amíg rá nem kap az ember az ízére. Egyszer kell jól megcsinálni, majd örökre használni.

Tesztelve 2024 június eleje, LM, bash alatt.