R.Wobst, www.ifw-dresden.de/~wobst/shell.html
Problem:
Einfache Lösung (ksh, zsh):
CDPATH=Dietmar:Sven:Axel:Andreas
--> aus dem Directory Telco kann man dann einfach mit "cd Witze" zu Axel wechseln.
Achtung!
$ pwd /home/Dietmar $ cd Telco ksh: cd: Telco: bad directory $
Richtig wäre gewesen: CDPATH=.:Dietmar:Sven:Axel:Andreas
$ pwd /home/Dietmar/Telco $ cd Witze /home/Axel/Witze $
"Heiko-Trick": CPATH=.:..:Dietmar...
Damit können auch Nichten und Neffen per "cd" gefunden werden:
$ pwd /home/Dietmar/Telco $ cd Windows /home/Dietmar/Windows $
Nachteil: Man kann dem Rechner nicht beibringen, dass es sowohl ../Windows als auch ../../Andreas/Windows gibt und man das zweite in der Liste meint.
Ausweg:
cd als Funktion programmieren ... umständlich.
In der Praxis kommen "cd ../dir" und "cd ../../dir" am häufigsten vor. Daher nutze ich folgende Shellfunktionen:
CD() { cd ../$1; } CD2() { cd ../../$1; }
Anwendung:
$ CD Windows $ CD2 Naideb
Mein CDPATH enthält weder ".." noch "../..".
Problem: mkdir Heiko; cd Heiko
... ewig diese Tipperei! Shellfunktion:
Mkdir() { mkdir $1 && cd $1; }
Problem: Wo bin ich?
"pwd" - klar. Schöner (bis heute!):
PS1='${PWD#$HOME/}> '
Wirkung:
Anwendung:
Dietmar/Telco> pwd /home/Dietmar/Telco Dietmar/Telco> cd /home> cd /etc/init.d /etc/init.d>
Optional: Rechnernamen integrieren (Vorsicht, lange Prompts!)
Problem:
"cd" quer durch den Baum geht schön; ich möchte gerne copyen/moven/linken
Lösung:
Shellskripte Mv, Cp, Ln:
Mv: _mvmvmv_ mv $* Cp: _mvmvmv_ cp $* Ln: _mvmvmv_ ln $*
Shellskript _mvmvmv_ (alt):
#!/bin/kshold=$PWD # PWD changes during cd cmd=$1; shift # arg1 = command
eval cd \$$# 2>&1 >/dev/null && # here CDPATH is used! { new=$PWD; cd $old list= while [ $# -gt 1 ] ; do list="$list $1"; shift; done $cmd $list $new; }
Anwendung:
Ln humbug preise agb Witze
Beachte: Wenn "Witze" nicht gefunden wird oder ein File ist (also "cd Witze" nicht klappt), richtet das Kommando keinen Schaden an!
Nutze ich mittlerweile weniger.
Problem: Ich möchte gern quer durch den gesamten Baum moven/copyen; CDPATH ist mir zu schwach.
Lösung:
Shellskripte CP, MV, GET:
CP: ls $* | cpio -o >~p MV: CP $* && rm -i $* GET: cpio -ivmd <~p
Hierbei ist $HOME/p eine Fifo:
$ cd $ mkfifo p $ chmod 660 p $ ls -l p prw-rw-rw- 1 milchbrat cdu 0 Apr 18 22:52 p
Anwendung:
vt1: Dietmar/Telco> CP humbug agb vt2: Alex/Witze> GET
Diese Tools nutze ich am laufenden Band zwischen virtuellen Screens (oder xterms, lassen sich aber nicht so schnell per Tastatur selektieren).
Die Fifo nutze ich auch zum Datentausch zwischen Exemplaren des vi/vim (vim kann es direkt per "visual", erfordert aber mehr Tastendrücke).
Problem: Ich möchte mir Files von einem anderen Rechner (sein Name ist in der Shellvariablen p2 enthalten) holen, die an gleicher Stelle liegen.
Lösung: Shellskript get2:
rsh $p2 cd $PWD \; find "$@" -print \| cpio -oc | cpio -ivmd
Problem: Wo finde ich den letzten Brief ans Finanzamt? Hieß vermutlich finanz... oder ...finanz...
Lösung unter Linux:
$ cd $ locate finanz
Nachteil: Nur unter Linux; wenn doch unter Linux ... ich habe den Brief erst heute früh geschrieben ... wo ist er bloß ...
Lösung:
Shellskript where:
find ${2:-.} -name "*$1*" -print | less
Anwendung:
$ cd $ where finanz # oder auch $ where finanz briefe # Directory /home/briefe existiert
Problem: Wo ist der Brief (Name? Keine Ahnung!), der Text oder WordPerfect-Format war und eine Passage wie "bitte ich um Verlängerung" (oder hieß es "Aufschub"?) enthielt? Habe den Brief vielleicht schon komprimiert (mit gzip? bzip2? weiß nicht mehr).
--> wie man sieht, ein Problem der Praxis.
Lösung: Mit gut Glück hilft
$ cd $ zfind "bitte ich um (Verl.*ngerung|Aufschub)"
zfind ist eine schwieriges Shellskript (nur 51 Zeilen), biete Download zusammen mit dem UNIX/open-Artikel aus Heft 5/2000 (Alltägliches Chaos) an: Daunlot hier!
Files werden ggf. mit konfigurierbaren Programmen dekomprimiert, gefundene egrep-Matches invers dargestellt (sehr nützlich), auch in Textverarbeitungsfiles kann man noch suchen; einzelne Filetypen und Directories lassen sich mit der Shellvariablen ZFIND_EXCL ausschließen.
--> Powertool. Arbeitet unter ksh wie unter bash (schwierig!)
Problem: Ich möchte die drei neuesten Files dekomprimieren. Ich weiß zwar, wie sie heißen (ls -t), aber die Namen sind so furchtbar lang, und ich bin so furchtbar faul.
Lösung: Shellskript fl ("file last"). Nicht trivial! Listet die neuesten 20 Files. Gibt man eine Zahl ein, z.B. 5, werden die 5 neuesten File geechoed. Gibt man mehrere Zahlen ein, werden genau diese Einträge selektiert. Gedacht für folgende Verwendung:
$ more $(fl) # alt: more `fl` 1 -rwxr-xr-x 1 wobst other 691 Apr 18 23:48 fl 2 drwxr-xr-x 2 wobst other 1024 Apr 18 21:44 Save 3 -rwxr-xr-x 1 wobst other 140 Mär 26 18:22 menc 4 -rwxr--r-- 1 wobst other 291 Mär 26 18:00 ab 5 -rwxr-xr-x 1 wobst other 19 Mär 25 22:18 sig 5 -rwxr-xr-x 1 wobst other 111 Mär 7 19:00 vic 7 -rwxr-xr-x 1 wobst other 45 Mär 3 12:04 csc Enter number(s): 1 ...Daunlot hier!
Es gibt drei Grundtypen von Nutzern:
Löscht alle Files, die älter als ein gewisses Datum sind - das Datum ist nicht bekannt. Skript sieht so aus:
ls -t -l $* | grep -v '^total' | pr -n -t | morewhile : do echo -n "delete files from no.: " read nr || exit 1 case "$nr" in ([1-9]|[1-9][0-9]|[1-9][0-9][0-9]) break;; (*) echo "sorry?"; continue;; esac done
ls -t $* | tail +$nr | xargs rm -f
Anwendung:
delold *k 1 -rwxr-xr-x 1 wobst other 2 Dez 20 12:46 drink 2 -rwxr-xr-x 1 wobst other 16000 Nov 11 21:39 lock 3 -rwxr--r-- 1 wobst other 409 Jun 16 2000 bck 4 -rwxr-xr-x 1 wobst other 438 Jul 6 1998 look 5 -rwxr-xr-x 1 wobst other 3384 Jan 5 1998 newwpcrack delete files from no.:
Sortiert Files, nach Alter geordnet, in Schubfächer (Directories). Gut z.B. zum Archivieren von Mail, nach Jahreszahlen gegliedert (brauche ich oft). Skript:
#!/bin/kshtypeset -i i=0 n
. ~/util/ask
ls -l -t | grep '^-' | nl -w3 | less
dask "Enter number" n || exit 1 dask "Enter dirname" name || exit 1
[ -d "$name" ] || mkdir $name || exit 1
ls -l -t | grep '^-' | while ((i < n)) do read line && set -- $line && eval mv \$$# $name ((i+=1)) done
In ~/util/ask steht u.a.:
dask() { typeset wordwhile : do if [ "$3" ] then print "$1 [$3]: \c" >/dev/tty else print "$1: \c" >/dev/tty fi
read word
if [ -z "$word" -a $# = 2 ] then error "Bitte eine nichtleere Eingabe" >/dev/tty continue else [ "$word" ] || word="$3" fi
break done
eval $2="\$word" return 0 }
Anwendung:
dirsplit 1 -rwxr-xr-x 1 wobst other 2 Dez 20 12:46 drink 2 -rwxr-xr-x 1 wobst other 16000 Nov 11 21:39 lock 3 -rwxr--r-- 1 wobst other 409 Jun 16 2000 bck 4 -rwxr-xr-x 1 wobst other 438 Jul 6 1998 look 5 -rwxr-xr-x 1 wobst other 3384 Jan 5 1998 newwpcrack Enter number: 2 Enter dirname: 02
... nacheinander Directories 02, 01, ... erzeugen und zuletzt "mv 02/* ." geben. Gewiss eleganter möglicht, reichte aber für die Praxis völlig aus.
Benutze ich viel!
Anwendung:
makecpio dirname[s] [filename[s]]
Beispiel:
$ ls -F wichtig/ muell/ $ ls -F muell agb witze/ config prot $ makecpio muell ... Press ENTER to remove, ^D if not: $ ls -F wichtig/ muell.cpio.gz
makecpio2 komprimiert mit bzip2!
Auspacken: uncpio muell make
Listen: uncpio muell list
(bzw. uncpio2)
Skripte:
makecpio =
case "$0" in (*2) CP=bzip2; suff=bz2;; (*io) CP=gzip; suff=gz;; esac( find $1 -print | cpio -oc | $CP -v >$1.cpio.$suff ) && { print "press ENTER to remove, ^D if not"; read word && rm -r -f $1; } ls -l $1.cpio.$suff
uncpio =
#!/bin/kshcase "$0" in (*2) CP=bunzip2; suff=bz2;; (*io) CP=gunzip; suff=gz;; esac
arch="$1" [ -f "$arch" ] || arch=$arch.cpio.$suff
[ -f "$arch" ] || { echo "file '$arch' does no exist!\07"; exit 1; } case "$2" in (list) key="t $3 | more";; (make) key="dm" [ "$3" ] && key="dm \"$3\"";; (*) echo "usage: $0 archive_name {list|make} [pattern_or_name]\07" exit 1 ;; esac $CP <$arch | eval cpio -iv$key
Ausweg: deNT
Transformiert die Filenamen in anstaendige (Steuerzeichen --> '_', Umlaute wie ä --> ae) und passt auf, dass kein Name doppelt entsteht (ggf. Anhängen einer Folgenummer).
Skript:
#!/bin/bash # rename files containing control characters and umlauts in their name # (C) Reinhard Wobst, @(#) 7.Apr 17:38typeset -i n
find . -print | while read fn do replace="$(echo -n "$fn" | tr '[\001-\040]' '[_*]')"
replace="$(echo "$replace" | sed -e 's-ä-ae-g' -e 's-ö-oe-g' -e 's-ü-ue-g' \ -e 's-Ä-Ae-g' -e 's-Ö-Oe-g' -e 's-Ü-Ue-g' \ -e 's-ß-ss-g' )"
[ "$replace" = "$fn" ] && continue
[ -a "$replace" ] && { n=0 while [ -a "$replace$n" ] ; do let n+=1; done replace="$replace$n" }
echo renaming \""$fn\"" to \""$replace\"" mv "$fn" "$replace" done | cat -vt | tee ${1:-.deNTprot}
Anwendung:
$ ls anstaendig anständig Müll mit Leerzeichen $ rm Müll* rm: Müll: no such file or directory $ deNT renaming "anständig" to "anstaendig1" renaming "Müll mit Leerzeichen" to "Muell_mit_Leerzeichen"
Problem: Ich möchte gern "rm" interaktiv haben, außer wenn ich schon selbst einen Schalter gesetzt habe (dann weiß ich, was ich mache).
Shellfunktion rm:
rm() { case "$1" in -f|-r|-i) /bin/rm $*;; *) /bin/rm -i $*;; esac }
Problem: Mein Chef taucht ab und zu unerwartet auf.
Lösung: Cheftastenfunktion ccc:
ccc() { clear; cd; }
Problem: Ich möchte tabs durch entsprechende Leerzeichenfolgen ersetzen.
Lösung: Skript detab
#!/bin/kshTMP=tmp$$.$(basename $0)
trap 'rm -f $TMP' 0 1 2 3 15
for i in $* do pr -t -e $i >$TMP [[ -n "$TMP" ]] && mv $TMP $i done
Anwendung:
detab agb witz15
Lösung: Skipt cyc
#!/bin/kshprint "$*" | IFS='; ' read prompt rest #!! Linux: zsh nehmen
while : do eval $* print "($prompt) >>>>>> Prrresss ENTE or die: \c" >/dev/tty read word
Anwendung:
$ cyc 'make && debug copt' ... (make) >>>>>> Press ENTE or die:Abbruch mit Interrupt oder ^D.
Problem: Ich komprimiere Files in einem bestimmten Directory üblicherweise und will nur die noch nicht komprimierten haben.Lösung: sehr simpel - lz
ls $* *[!z]Das "$*" reserviert Platz für Schalter:
$ ls -F humbug oldhumbug.gz witze/ $ lz humbug oldhumbug.gzwitz: witz1 witz2 ... $ lz -d -F humbug witze/
Anwendung:
$ gzip -v $(lz)
Problem: Ich möchte auf jedem virtuellen Screen eine eigene History haben.Lösung: Im Profile folgenden Eintrag unterbringen (Linux):
HISTFILE=$(tty | sed -e 's-/-.-g' -e "s-^-$HOME/.hist-")Anwendung:
$ ls -l .h* -rw-r--r-- 1 wobst asw 1649 Apr 19 15:47 .hist.dev.pts.0 -rw-r--r-- 1 wobst asw 2326 Apr 19 14:59 .hist.dev.pts.1 -rw-r--r-- 1 wobst asw 15 Mar 3 17:18 .hist.dev.pts.10 -rw-r--r-- 1 wobst asw 2509 Apr 19 14:59 .hist.dev.pts.2 -rw-r--r-- 1 wobst asw 1527 Apr 19 14:59 .hist.dev.pts.3 -rw-r--r-- 1 wobst asw 1830 Apr 18 22:22 .hist.dev.pts.4 -rw-r--r-- 1 wobst asw 1904 Apr 19 00:36 .hist.dev.pts.5 -rw-r--r-- 1 wobst asw 1779 Apr 15 22:58 .hist.dev.pts.6 -rw-r--r-- 1 wobst asw 1870 Apr 15 22:58 .hist.dev.pts.7 -rw-r--r-- 1 wobst asw 1216 Apr 15 22:58 .hist.dev.pts.8 -rw-r--r-- 1 wobst asw 211 Mar 3 22:56 .hist.dev.pts.9
Hier nochmals der Link zur Erinnerung:www.ifw-dresden.de/~wobst/shell.html