"Flexnek ajánlom..."
Van egypár függvény, amit minden bash-es környezetben installálni szoktam. Ilyenek az "lm" (eredetileg az "ls -l|more" rövidítése volt), a "..", "...", ... család stb. Most sikerült végre jónehány korábbról maradt ötletet lekódolnom bash alá. Hátha érdekes lehet másnak is, ezért közreadom...
-
cd FILE
A Total Commander-ben nagyon tetszik az a lehetőség, hogy ha egy teljes path-t másolunk be a command prompt-jába (amint mondjuk egy find kimeneteként kaptunk), akkor is odamegy, ha a path vége egy file. Ezt ültettem át bash-ba. Persze a Total Commander kijelöli a keresett file-t, amit értelemszerűen nem valósítottam meg. Még azon gondolkodom, hogy ebben az esetben beállítanám a CDFILE nevű környezeti változót (a CDPATH mintájára), de ez még nincs teljesen végiggondolva. Lássuk hát a cd renormált változatát. Nem biztos, hogy teljesen jól kezeli a -L és -P opciókat, de mivel ezeket még életemben nem használtam, ezért engem meglehetősen nagy valószínűséggel nem fog zavarni. Ímhol a módosított "cd" parancs:# enable cd path/file (like in Total Commander)
cd() { [ $# -eq 0 ] && command cd;
local arg f; declare -a arg; [[ "$1" =~ ^-[LP]$ ]] && arg=("$1") && shift
f="$1" ; [ -f "$f" ] && f=${f%/*}; arg+=("$f"); command cd "${arg[@]}";}
export -f cdEz ha az argumentum egy file-ra mutat, akkor levágja a file-t és szépen odamegy a maradvány könyvtár névre. Egyébként meg pont úgy működik, ahogy a bash beépített cd-je.
-
find: egyszerűbben
Szintén régi álmom volt, hogy a "find"-nak ne kelljen megadni folyton a "-name" opciót, ha csak egy mintát keresünk. Annyit csináltam, hogy ha a megadott egyetlen arg nem egy dir, vagy symlink, vagy file, akkor átalakítja a kérést -name-esre.# Simplified find. With one arg just find that pattern
find() { [ $# -eq 1 -a ! -d "$1" -a ! -L "$1" -a ! -f "$1" ] && set -- -name "$1"; command find "$@";}
export -f findSzóval most már mehet a 'find *.cpp' stílusban. Akkor van gond, ha mondjuk a CVS könyvtárakat
keressük és a cwd-ben is már ott van a CVS. Akkor expliciten meg kell adni a -name opciót. Lehet, hogy a könyvtár, symlink, file ellenőrzést el lehetne hagyni. Egyelőre nem okozott problémát, ezért így kísérleti verzióként így marad. -
ls: könyvtárak előre
Engem speciel picinyként zavart, hogy ha listázom a könyvtár file-jait, akkor név szerint rendezi sorrendbe alapból. Jobban szeretem a Total Commander-es megoldást, ahol a könyvtárak elől vannak. Találtam is erre egy külön opciót, de ha régi ls(1) használunk, akkor kell egy kis kézi mókolás:Új bash-ban:
lm (){ ls --color -l --group-directories-first -h "$@" | less -eRrXF;}
export -f lmRégi verzió:
# Emulate missing --group-directories-first
lm() { ls -l --color -h "$@"|awk 'NR==1||/^d/{print;next};{f[n++]=$0}END{for(i=0;i<n;++i)print f[i]}'|less -eRrXF;}
export -f lmA -h opció a méreteket kiegészíti a K, M, G-vel, így szerintem olvashatóbb. A less nem vár karakter leütést, ha egy képernyőre elfér a kimenet, illetve nem törli le a kimenetét. Továbbá átengedi az "ls --color" színező escape szekvenciáit.
-
cd ../../..
Már nagyon rég kimódoltam, hogy a cd ../../.. kelgyók helyett a rövidebb ".." (cd .. helyett), "..." (cd ../..), "...." (cd ../../..) stb. függvényeket használom. Szerintem nagyon intuitív és hatékony megoldás, bár sajnos a "." foglalt. (Szerénység! Ne tömjénezze magát! Szerénység!) Kifejezetten hiányolom, ha új környezetben kell téblábolnom. Egy hiányossága volt eddig. Nem lehetett command line argumentumban beírni, ha felfelé szerettünk volna menni. De most már az is megvan! Sőt az automatikus könyvtár kiegészítés is megy. Annyiban különbözik a cd-től, hogy a könyvtárakra szűkítettem a felajánlott neveket. Bár lehet, hogy az összes file kiírása meg segítené a tájékozódást (és az új cd-vel oda is tudna menni). No, majd meglátom. A korábbiakhoz képest azt is egyszerűsítettem, hogy egy for ciklus gyártja le az összes függvényt az autocomplete résszel együtt. Az alábbi részletet kell a .bash_profile-ba, vagy igény szerint a .bashrc-be kell beletenni. Az autocomplete-hez kellett egy kis segítség, amit >innen< szedtem. No meg a man bash(1)-ből.#
# Auto completion function
#
__dotdot_completion() { local p n=${#COMP_WORDS};
for((--n;n;--n)){ p+=../;}; IFS=$'\n';
COMPREPLY=($(command cd $p&&command ls -d ${COMP_WORDS[1]}*/ 2>/dev/null));
}
export -f __dotdot_completion
# Define a lot of .. functions
n=..
unset p
for((;${#n}<10;)){ p+="../"; eval "$n(){ command cd $p\"\$1\";}";
export -f $n; command complete -o nospace -o filenames -F __dotdot_completion $n; n+=.;
}
unset p nÍgy most már megy a "$ .. <TAB><TAB>", amikor is kilistázza a szülő könyvtár alatti könyvtárakat.
-
Prompt
Nem szeretem a feleslegesen hosszú prompt-okat, ezért én az alábbit szoktam használni. Előnye, hogy benne van a használt terminál neve (ez akkor jó, ha mondjuk a gdb-ben a kimenetet átirányítjuk) és hogy az adott bash hanyadik gyerek, azaz ^D-re becsukja-e az ablakot, vagy csak eggyel feljebb lép. Ez utóbbi tényleg nem nagyon hasznos (hiszen a bash szól, ha olyan ablakból akarunk kilépni, amelyikben vannak háttérben futó processzek), de párszor jól jön.
export PS1="\w [\l:\j]\$ "
És egy példa:
~ [2:0]$ tty
/dev/pts/2
~ [2:0]$ vim
^Z
[1]+ Stopped vim
~ [2:1]$ logout
There are stopped jobs.
~ [2:1]$ fg
:q
~ [2:0]$ -
Közös függvények
A függvények elején be szoktam tölteni pár perl szerűen használható függvényt. A die és warn kiírja az üzenetet és a hívó sor számát az stderr-re, az oops és damn pedig ezen felül a teljes call stack-et is kiírja. A getARGS pedig megkönnyíti a getopts beépített függvény használatát és definiál egy csomó környezeti változót ARG_<arg> formátumban. Még a helpet is legenerálja nekünk. Például ha a szkriptünk elején meghívjuk a következő sort:
getARGS "ab:" "-a Csinál valamit" "-b FILE - Mást csinál"
és szkriptünket meghívjuk a "-a -b Akarmi" paraméterekkel, akkor a $ARG_a értéke 1 és $ARG_b értéke 'Akarmi' lesz. A "-h"-t nem kell megadnunk, mert az alapból kezeli. Ha ilyen argumentumot talál, akkor egy hevenyészett helpet ír ki. A fel nem dolgozott argumentumokat az ARGS tömbben adja vissza (pl: olyan argumentumot talál, ami nem kötőjellel kezdődik, vagy amiket a '--' arg után adunk meg).#!/usr/bin/bash
#
# Common bash functions
#
# v0.004, 2014-09-09, TrueY
#
########################################################
warn() { read a b < <(caller); echo "$@ at line $b:$a" >&2;}
die() { read a b < <(caller); echo "$@ at line $b:$a" >&2; exit 1;}
oops() { echo "$@">&2; local n=0
while read a b c < <(caller $n); do
echo " at func '$b' at line $c:$a"; ((++n));
done >&2
}
damn() { echo "$@">&2; local n=0
while read a b c < <(caller $n); do
echo " at func '$b' at line $c:$a"; ((++n));
done >&2
exit 1;
}
# traslate command line arguments to env var ARG_<opt>=val
# Older bash does not provide hash arrays
# First arg is the accepted args, all others are for halfhearted help
# if -h presented as arg, show help text automatically
getARGS() {
[ $# -eq 0 ] && warn "$FUNCNAME: Bad number of args" && return 1
local OPTS="$1"; shift; ARGS=() # declare -a makes it local
HELP="\nUsage: ${0##*/}"
for((i=0;i<${#OPTS};++i)){
local c=${OPTS:i:1}
if [ "$c" == : ]; then HELP+=" <ARG>"
else HELP+=" -$c"
fi
}
HELP+="\n\n -h - This help text.\n"
for((;$#;)){ HELP+=" $1\n"; shift;}
# BASH_ARGV is in reverse order
for((i=${#BASH_ARGV[@]}-1;i>=0;--i)){
[ "${BASH_ARGV[$i]}" == -h ] && echo -e $HELP && exit 0;
ARGS+=("${BASH_ARGV[$i]}");
}
OPTIND=1 # Reset for any case
while getopts "$OPTS" arg "${ARGS[@]}"; do
[ $arg == "?" ] && echo "Use -h option for help!" && return 1
eval "ARG_$arg='${OPTARG:-1}'"
done
ARGS=("${ARGS[@]:OPTIND-1}") # Get the remaining options
return 0
}Ez a file a bash szkriptek elején a ". ~/common_bash_functions" hívással tölthető be.
Hát ennyit mára a bash világából.
Definiálódjunk minden nap!
+jegyzések