rfhpc8132% ls -la /bin/ls -r-xr-xr-x 1 root wheel 265856 Nov 17 2000 /bin/ls
rfhpc8132% file /usr/bin/true /usr/bin/true: Bourne shell script text executable rfhpc8132% file /bin/ls /bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1, statically linked, stripped
rfhpc8132% head -1 /usr/bin/true #! /bin/sh rfhpc8132% head -1 /bin/ls ELF```ab`4Ø c4 b(po`€€^¿b^¿bo``¿bhO
rfhpc8132% size /bin/ls text data bss dec hex filename 245439 2664 19900 268003 416e3 /bin/ls
rfhpc8320% cp /soft/local/www/InfoPortal/images/welcome3.gif /tmp rfhpc8320% ls -l /tmp/welcome3.gif -rw-rw-r-- 1 feyrer bedienst 2599 Apr 16 12:41 /tmp/welcome3.gif rfhpc8320% file /tmp/welcome3.gif /tmp/welcome3.gif: GIF file, v87 rfhpc8320% chmod +x /tmp/welcome3.gif rfhpc8320% ls -l /tmp/welcome3.gif -rwxrwxr-x 1 feyrer bedienst 2599 Apr 16 12:41 /tmp/welcome3.gif rfhpc8320% /tmp/welcome3.gif /tmp/welcome3.gif: GIF87a\344\336\2003\231\377\377\377,\344\336^B\376\204\217\251\313\355^O\243\234\264\332\213\263\336\274\373^O\206\342H\226\346\211\246\352\232^E^A^K\307\362L\271\364\215\347\254\255\367\376\277\341^A\207\304\242BhL*u\310\245\363\251r5\241\324\352G\372\262j\267-,\367^K\216x\303\3442^B: not found /tmp/welcome3.gif: 5\253\253\336\354\372\315\266\245\341\364\263Ojp\327\367v: not found /tmp/welcome3.gif: ^^\240\307\2677^W\203^FxXB^H3^VH\263\230\250\361\342(\323HYx^Y^Y\224\2273v\330^I\251i!\227^Y\365\367y#z\305^Sj\342: not found /tmp/welcome3.gif: X\272Z\201\344*b\310\371\2305K[szj: not found /tmp/welcome3.gif: syntax error at line 3: `)' unexpected
Die hier gezeigten Fehlermeldungen stammen von der /bin/sh!
Binary | Name | Eigenheit |
---|---|---|
sh | Bourne-Shell | Kleinster gemeinsamer Nenner zwischen sh, ksh, bash, zsh => Portabilitaet. Vorlesungsinhalt! |
ksh | Korn Shell | sh + etwas mehr |
bash | Bourne-Again Shell | sh + einiges mehr |
csh | C-Shell | Komplett eigene Shell, historisch interessant |
tcsh | Tenex C-Shell | csh + einiges mehr; Interaktive Shell an der FH, nicht zum Programmieren empfohlen! |
zsh | Z-Shell | sh + viel zuviel mehr |
rfhpc8320% date 2>x date: bad conversion usage: date [-u] mmddHHMM[[cc]yy][.SS] date [-u] [+format] date -a [-]sss[.fff] rfhpc8320% sh $ date 2>x Wed Apr 16 12:33:03 MEST 2003 $
Hinweis: An der FH Regensburg liegen Kopien der Dot-Files in /home3/bedienst/dummy.
$ echo test >x $ date >x $ cat x Tue Oct 30 17:34:47 CET 2001
Aber Vorsicht:
$ sort datei >datei
Hierbei wird bereits vor dem Start von sort(1) "datei" gelöscht! Übliche LÖsung:
$ sort datei >datei.neu $ mv datei.neu datei
$ date >>x $ cat x Tue Oct 30 17:34:47 CET 2001 Tue Oct 30 17:41:46 CET 2001
$ ls gibtsnicht 2>fehler $ cat fehler ls: gibtsnicht: No such file or directory $ ls /bin/ls gibtsnicht 2>fehler /bin/ls $ cat fehler ls: gibtsnicht: No such file or directory
$ ls /bin/ls gibtsnicht 2>&1 ls: gibtsnicht: No such file or directory /bin/ls $ ls /bin/ls gibtsnicht >output 2>&1 $ cat output ls: gibtsnicht: No such file or directory /bin/ls
Achtung, Reihenfolge ist hier wichtig!
$ head -2 </etc/group wheel:*:0:root,feyrer daemon:*:1:daemon
$ head -2 <<ENDE > eins > zwei > drei > vier > ENDE eins zwei
$ cat /etc/passwd >/tmp/t $ grep root </tmp/t root:*:0:0:Charlie &:/root:/bin/sh $ cat /etc/passwd | grep root root:*:0:0:Charlie &:/root:/bin/sh $ ps -auxwww USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND root 0 0.0 7.4 0 14456 ?? DLs Thu03PM 0:00.32 (swapper) feyrer 3297 0.0 0.1 372 180 p6 R+ 5:59PM 0:00.00 ps -auxwww feyrer 3251 0.0 0.2 556 340 p6 S 5:42PM 0:00.08 sh feyrer 3201 0.0 0.6 944 1216 p6 Is 5:12PM 0:00.18 -csh (tcsh) root 3200 0.3 1.7 2104 3296 ?? R 5:12PM 0:00.74 xterm ... $ ps -auxwww | grep /netscape feyrer 3177 0.0 6.6 17668 13040 ?? S 5:06PM 0:12.94 /usr/pkg/lib/netscape/communicator-4.76/netscape feyrer 3282 0.0 0.0 556 4 p6 R+ 5:57PM 0:00.00 grep /netscape (sh) $ ps -auxwww | grep /netscape | grep -v grep feyrer 3177 0.0 6.6 17668 13040 ?? S 5:06PM 0:12.94 /usr/pkg/lib/netscape/communicator-4.76/netscape $ ps -auxwww | grep /netscape | grep -v grep | awk '{ print $2 }' 3177 $ ps -auxwww | grep /netscape | grep -v grep | awk '{ print $2 }' | xargs echo kill kill 3177 $ ps -auxwww | grep /netscape | grep -v grep | awk '{ print $2 }' | xargs echo kill | sh -v kill 3177
rfhinf108% en oracle-10.1.0.2 sourcing /soft/oracle-10.1.0.2/install/en_oracle-10.1.0.2 rfhinf108% echo 'select * from test;' | sqlplus feyrer/feyrer@ora10g | tail -n +14 | sed '/^$/,$d' 1 2 3 4 5 6 7 17 42 12375789
$ file bla.gif bla.gif: GIF file, v89 $ cat x cat bla.gif | giftopnm | pnmrotate -90 | ppmtogif >bla2.gif $ sh x ppmtogif: computing colormap... ppmtogif: 246 colors found $ file bla2.gif bla2.gif: GIF file, v87
bla.gif | bla2.gif |
$ grep root /etc/passwd | sed 's/:.*//' root
$ grep root /etc/passwd | tee r | sed 's/:.*//' root $ cat r root:*:0:0:Charlie &:/root:/bin/sh
$ cc listargs.c -o listargs $ ./listargs argc = 1 argv[0] = "./listargs" argv[1] = NULL $ $ ./listargs foo "bar baz" argc = 3 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar baz" argv[3] = NULL $
$ cd /etc/ssh $ ls ssh* ssh_host_dsa_key ssh_host_key ssh_host_rsa_key ssh_host_dsa_key.pub ssh_host_key.pub ssh_host_rsa_key.pub $ cd /etc $ ls pas* passwd $ ls *wd passwd $ ls p*d passwd path_to_inst.old $ ls p*w*d passwd
Was geschieht Shell-intern?
$ cd /etc/ssh $ echo ssh* wird ersetzt zu: echo ssh_config ssh_host_dsa_key ssh_host_dsa_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub sshd_config und ergibt: ssh_config ssh_host_dsa_key ssh_host_dsa_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub sshd_configbzw. mit listargs:
$ /home3/bedienst/feyrer/public_html/SA/SS2004/listargs ssh* argc = 7 argv[0] = "/home3/bedienst/feyrer/public_html/SA/SS2004/listargs" argv[1] = "ssh_config" argv[2] = "ssh_host_dsa_key" argv[3] = "ssh_host_dsa_key.pub" argv[4] = "ssh_host_rsa_key" argv[5] = "ssh_host_rsa_key.pub" argv[6] = "sshd_config" argv[7] = NULL
$ cd /etc $ ls -Fd rc? rc0@ rc1@ rc2@ rc3@ rc5@ rc6@ rcS@ rcm/ $ echo *.? cron.d init.d rc0.d rc1.d rc2.d rc3.d rcS.d
$ cd /etc $ ls -ld rc[0-9Ss] lrwxrwxrwx 1 root root 11 Jan 3 2001 rc0 -> ../sbin/rc0 lrwxrwxrwx 1 root root 11 Jan 3 2001 rc1 -> ../sbin/rc1 lrwxrwxrwx 1 root root 11 Jan 3 2001 rc2 -> ../sbin/rc2 lrwxrwxrwx 1 root root 11 Jan 3 2001 rc3 -> ../sbin/rc3 lrwxrwxrwx 1 root root 11 Jan 3 2001 rc5 -> ../sbin/rc5 lrwxrwxrwx 1 root root 11 Jan 3 2001 rc6 -> ../sbin/rc6 lrwxrwxrwx 1 root root 11 Jan 3 2001 rcS -> ../sbin/rcS
[!a-z] - Alle Zeichen ausser a-z
$ echo w* wall whodo wtmpx $ echo w\* w* $ echo rc?.d rc0.d rc1.d rc2.d rc3.d rcS.d $ echo rc\?.d rc?.d $ $ touch a\ b (Leerzeichen nicht als Argumen-Trenner) $ ls -l a?b -rw-r--r-- 1 feyrer bedienst 0 Nov 6 00:08 a b $ $ ls \ (Befehl am Zeilenende nicht ausfuehren) > | wc -l 19 $ $ echo \\. \.
Obwohl Ähnlich bestehen dennoch Unterschiede zwischen Wildcards in der Shell und regulären Ausdrücken!
$ ls -la total 16 drwxr-xr-x 2 feyrer bedienst 142 Nov 5 21:20 . drwxrwxrwt 10 root sys 831 Nov 5 21:20 .. -rw-r--r-- 1 feyrer bedienst 0 Nov 5 21:20 .foo -rw-r--r-- 1 feyrer bedienst 0 Nov 5 21:20 bar $ echo * bar $ rm * $ ls -la total 16 drwxr-xr-x 2 feyrer bedienst 106 Nov 5 21:21 . drwxrwxrwt 10 root sys 831 Nov 5 21:20 .. -rw-r--r-- 1 feyrer bedienst 0 Nov 5 21:20 .foo $
$ echo gibt*es*sicher*nicht gibt*es*sicher*nicht $ ls gibt*es*sicher*nicht gibt*es*sicher*nicht: No such file or directory
Die Fehlermeldung des zweiten Befehls hier stammt vom ls(1)-Befehl, nicht von der Shell!
$ touch x y z a b c $ echo * a b c x y z $ echo [xzac] a c x z $ $ cd /bin $ echo *s alias apropos auths bfs bzless compress ctags daps dumpcs dumpkeys getopts groups gzless ipcs jobs less listusers loadkeys logins ls mailstats mkisofs mkmsgs newaliases news nisdefaults nisls pargs pfiles pflags pkgtrans pppstats praliases profiles projects ps pvs roles rusers sotruss strings tabs truss unalias uncompress units unix2dos whatis whocalls whois xargs yes $ echo *es newaliases pfiles praliases profiles roles yes
Ansonsten wird in Shells die die Tilde unterstützen diese ebenfalls von der Shell expandiert, nicht von Anwendungsprogrammen:
rfhpc8320% sh $ echo ~ ~ $ /bin/csh rfhpc8320% echo ~ /net/rfhs8012/home3/bedienst/feyrer rfhpc8320% echo ~dummy /home3/bedienst/dummy rfhpc8320% exit rfhpc8320% $ $ $ bash rfhpc8320$ echo ~ /home3/bedienst/feyrer rfhpc8320$ exit exit $
$ anzahl=1 $
$ echo $anzahl 1 $ echo $anzahlmal $ echo ${anzahl}mal 1mal
$ cd /var $ x=* (!!!) $ echo $x adm audit crash cron dmi dt inet ld ldap log lp mail news nfs nis ntp opt preserve run sadm saf snmp spool statmon tmp uucp yp $ echo "$x" ("" expandieren Variablen, aber keine Wildcards) * $ $ y=\* Sicherstellen, dass * nicht expandiert wird $ echo $y adm audit crash cron dmi dt inet ld ldap log lp mail news nfs nis ntp opt preserve run sadm saf snmp spool statmon tmp uucp yp $ echo "$y" * $
$ foo=bar $ sh (Neuer Prozess!) $ echo $foo $ exit $ $ foo=baz $ export foo (Shell-Variable ins Environment exportieren) $ sh $ echo $foo baz $ exit $
$ echo $HOME /net/rfhs8012/home3/bedienst/feyrer $ HOME=/etc $ cd $ pwd /etc
$ echo $USER feyrer
$ echo $SHELL /soft/bin/tcsh
$ cd /tmp $ cat >mydate <<EOF > #!/bin/sh > echo es ist: `date` > EOF $ chmod +x mydate $ $ /tmp/mydate es ist: Mon Nov 5 23:25:16 MET 2001 $ `pwd`/mydate es ist: Mon Nov 5 23:25:16 MET 2001 $ ./mydate es ist: Mon Nov 5 23:25:16 MET 2001 $ $ mydate mydate: not found $ echo $PATH /soft/X11R6/bin:/usr/openwin/bin:/soft/bin:/net/rfhs8012/home3/bedienst/feyrer/bin:/bin:/usr/ccs/bin:/usr/bsd:/usr/bin:/usr/sbin:/sbin:/usr/bin/X11:/usr/ucb:/etc:/usr/etc:/bin:/usr/bin:/usr/sbin:/sbin:/usr/ucb:/etc:/net/rfhs8012/home3/bedienst/feyrer/bin $ PATH=.:$PATH $ echo $PATH .:/soft/X11R6/bin:/usr/openwin/bin:/soft/bin:/net/rfhs8012/home3/bedienst/feyrer/bin:/bin:/usr/ccs/bin:/usr/bsd:/usr/bin:/usr/sbin:/sbin:/usr/bin/X11:/usr/ucb:/etc:/usr/etc:/bin:/usr/bin:/usr/sbin:/sbin:/usr/ucb:/etc:/net/rfhs8012/home3/bedienst/feyrer/bin $ mydate es ist: Mon Nov 5 23:25:16 MET 2001 $
$ echo $DISPLAY :0.0 $ unset DISPLAY $ xclock Error: Can't open display: $ DISPLAY=:0.0 $ xclock Error: Can't open display: $ export DISPLAY $ xclock (xclock geht auf :-)
$ echo $EDITOR vi $ echo $VISUAL vi
$ echo $PS1 $ $ echo x${PS1}x x$ x $ PS1=`uname -n`\$\ (Space nach Backslash!) rfhpc8317$
$ echo $MANPATH /usr/man:/net/rfhs8012/home3/bedienst/feyrer/man:/soft/X11R6/man:/usr/openwin/man:/soft/man:/usr/share/man:/usr/share/catman:/usr/catman:/usr/man $ MANPATH= $ export MANPATH $ man ls No manual entry for ls. $ MANPATH=/usr/share/man $ export MANPATH $ man ls User Commands ls(1) NAME ls - list contents of directory
$ echo $TERM xterm $ $ bold=`tput smso` $ boldoff=`tput rmso` $ echo "das ist ${bold}fett${boldoff} geschrieben" das ist fett geschrieben $ $ TERM=wy-50 $ export TERM $ bold=`tput smso` $ boldoff=`tput rmso` $ echo "das ist ${bold}fett${boldoff} geschrieben" das ist tfett0 geschrieben $
$ echo $CVS_RSH ssh $ CVSROOT=anoncvs@anoncvs.netbsd.org:/cvsroot $ export CVSROOT $ cvs co src The authenticity of host 'anoncvs.netbsd.org (204.152.184.161)' can't be established. RSA key fingerprint is a0:b1:35:d7:56:be:2c:30:78:b0:21:df:43:d9:64:5c. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'anoncvs.netbsd.org,204.152.184.161' (RSA) to the list of known hosts. U src/BUILDING U src/BUILDING.mdoc U src/Makefile U src/Makefile.inc ...
$ env DISPLAY=:0.0 EDITOR=vi GZIP=-9 HOME=/net/rfhs8012/home3/bedienst/feyrer NNTPSERVER=news.uni-regensburg.de TERM=xterm USER=feyrer ... foo=baz
Mit Hilfe des env-Befehls können ausserdem Umgebungsvariablen Shell-unabhängig(!) für die Dauer eines Befehls gesetzt werden:
$ BLA=xx $ export BLA $ blaprog args $ unset BLA
% setenv BLA xx % blaprog args % unsetenv BLA
$ env BLA=xx blaprog args $ env PREFIX=/usr/local make install
In der (Bourne) Shell existieren drei Arten von Anführungszeichen. Sie dienen dazu die Shell davon abzuhalten, bestimmte Expansionen automatisch vorzunehmen (Wildcards, Variablen, ...) bzw. um Argumente, Wildcards und Variable zu schützen:
$ date Wed Nov 7 00:13:20 MET 2001 $ ./listargs `date` argc = 7 argv[0] = "./listargs" argv[1] = "Wed" argv[2] = "Nov" argv[3] = "7" argv[4] = "00:13:19" argv[5] = "MET" argv[6] = "2001" argv[7] = NULL
$ ls -l $SHELL -rwxr-xr-x 1 root other 316916 Mar 26 1999 /soft/bin/tcsh $ ./listargs `ls -l $SHELL` argc = 10 argv[0] = "./listargs" argv[1] = "-rwxr-xr-x" argv[2] = "1" argv[3] = "root" argv[4] = "other" argv[5] = "316916" argv[6] = "Mar" argv[7] = "26" argv[8] = "1999" argv[9] = "/soft/bin/tcsh" argv[10] = NULL
$ ./listargs `ls -d /etc/rc?.d` argc = 6 argv[0] = "./listargs" argv[1] = "/etc/rc0.d" argv[2] = "/etc/rc1.d" argv[3] = "/etc/rc2.d" argv[4] = "/etc/rc3.d" argv[5] = "/etc/rcS.d" argv[6] = NULL
$ ls /etc/ssh* /etc/ssh_host_dsa_key /etc/ssh_host_key.pub /etc/ssh_host_dsa_key.pub /etc/ssh_host_rsa_key /etc/ssh_host_key /etc/ssh_host_rsa_key.pub $ ./listargs `ls /etc/ssh*` argc = 7 argv[0] = "./listargs" argv[1] = "/etc/ssh_host_dsa_key" argv[2] = "/etc/ssh_host_dsa_key.pub" argv[3] = "/etc/ssh_host_key" argv[4] = "/etc/ssh_host_key.pub" argv[5] = "/etc/ssh_host_rsa_key" argv[6] = "/etc/ssh_host_rsa_key.pub" argv[7] = NULL
$ ./listargs foo "bar baz" argc = 3 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar baz" argv[3] = NULL
$ ./listargs "$HOME" argc = 2 argv[0] = "./listargs" argv[1] = "/net/rfhs8012/home3/bedienst/feyrer" argv[2] = NULL
$ ./listargs "*" argc = 2 argv[0] = "./listargs" argv[1] = "*" argv[2] = NULL
$ ./listargs "`date`" argc = 2 argv[0] = "./listargs" argv[1] = "Do Apr 21 12:40:34 CEST 2005" argv[2] = NULL
$ ./listargs "double quote: \"" argc = 2 argv[0] = "./listargs" argv[1] = "double quote: "" argv[2] = NULL
$ ./listargs foo 'bar baz' argc = 3 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar baz" argv[3] = NULL
$ ./listargs '$HOME' argc = 2 argv[0] = "./listargs" argv[1] = "$HOME" argv[2] = NULL
$ ./listargs '*' argc = 2 argv[0] = "./listargs" argv[1] = "*" argv[2] = NULL
$ ./listargs '`date`' argc = 2 argv[0] = "./listargs" argv[1] = "`date`" argv[2] = NULL
Single Unix Specification Version 3, "2.2.2 Single-Quotes:":
``Enclosing
characters in single-quotes ( '' ) shall preserve the literal value of
each character within the single-quotes. A single-quote cannot occur
within single-quotes.''
$ ./listargs 'single quote: \'' > > > ^C $ ./listargs 'single quote: '\' argc = 2 argv[0] = "./listargs" argv[1] = "single quote: '" argv[2] = NULL
$ ./listargs foo bar\ baz argc = 3 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar baz" argv[3] = NULL
$ ./listargs \* argc = 2 argv[0] = "./listargs" argv[1] = "*" argv[2] = NULL
$ ./listargs \$HOME argc = 2 argv[0] = "./listargs" argv[1] = "$HOME" argv[2] = NULL
$ ./listargs \`date\` argc = 2 argv[0] = "./listargs" argv[1] = "`date`" argv[2] = NULL
$ ls bla bla: No such file or directory $ echo $? 2 $ ls -d . . $ echo $? 0 $ test -d . $ echo $? 0 $ test -f . $ echo $? 1 $
Ein Rückgabewert ==0 ist hier als ERFOLG zu werden, ein Wert != 0 ist als FEHLER zu werten. (Anders als bei den Wahrheitswerten in C!)
$ echo $$ 8800 $ ps -ef | grep 8800 feyrer 8800 8789 0 23:23:25 pts/14 0:00 sh feyrer 8847 8800 0 23:38:36 pts/14 0:00 grep 8800
$ xclock & 8851 $ echo $! 8851 $ pid=$! $ kill $pid $ 8851 Terminated $
$ cat scr echo $# $ $ ./scr a b c 3 $ ./scr a "b c" 2
$ cat ./scr echo $* ./listargs $* ./listargs "$*" $ $ ./scr Argc = 1 argv[0] = "./listargs" argv[1] = NULL argc = 2 argv[0] = "./listargs" argv[1] = "" (leeres Argument!) argv[2] = NULL $ $ $ ./scr foo foo argc = 2 argv[0] = "./listargs" argv[1] = "foo" argv[2] = NULL argc = 2 argv[0] = "./listargs" argv[1] = "foo" argv[2] = NULL $ $ ./scr foo "bar baz" foo bar baz argc = 4 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar" argv[3] = "baz" argv[4] = NULL argc = 2 argv[0] = "./listargs" argv[1] = "foo bar baz" (XXX) argv[2] = NULL
$ cat scr echo $#: $@ ./listargs $@ echo $#: "$@" ./listargs "$@" $ $ ./scr foo "bar baz" 2: foo bar baz argc = 4 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar" argv[3] = "baz" argv[4] = NULL 2: foo bar baz argc = 3 argv[0] = "./listargs" argv[1] = "foo" argv[2] = "bar baz" (OK!) argv[3] = NULL
Zur Weitergabe aller an ein Script übergebenen Parameter ist als einziges "$@" (inkl. Anführungszeichen) zu verwenden!
$ cat scr echo $0 $ ./scr ./scr $ /tmp/scr /tmp/scr $ $ PATH=.:$PATH $ export PATH $ scr scr
$ cat scr echo 1=$1, 2=$2 $ $ ./scr "baz bar" foo 1=baz bar, 2=foo
Beispiel 1:
$ cat scr set a b c echo 1=$1, 2=$2 $ $ ./scr x y z 1=a, 2=bBeispiel 2:
$ ls -l /etc/passwd -rw-r--r-- 1 root root 1544 2005-03-15 13:38 /etc/passwd $ set x `ls -l /etc/passwd` $ echo /etc/passwd ist $6 Bytes gross /etc/passwd ist 1544 Bytes gross
$ cat scr echo 1=$1, 2=$2, 3=$3, anz=$# shift echo 1=$1, 2=$2, 3=$3, anz=$# shift echo 1=$1, 2=$2, 3=$3, anz=$# shift echo 1=$1, 2=$2, 3=$3, anz=$# $ ./scr a b c 1=a, 2=b, 3=c, anz=3 1=b, 2=c, 3=, anz=2 1=c, 2=, 3=, anz=1 1=, 2=, 3=, anz=0
$ x=1 $ echo $x 1 $ x=`expr $x + 1` $ echo $x 2
Diskutiere den Einsatz von Shell-Wildcards, Anfuehrungszeichen sowie die Auswirkungen von getopt(3)!
$ cat scr if test -f /etc/shadow ; then echo Shadow Passwords in use fi $ sh scr Shadow Passwords in use $ cat scr if [ "$1" = "" ]; then echo Usage: $0 arg exit 1 fi $ sh scr Usage: scr arg $ sh scr foo $ $ cat scr if grep root /etc/passwd then echo root is home - all is well else echo ALARM: no root in /etc/passwd fi $ sh scr root:x:0:1:Super-User:/root:/sbin/sh root is home - all is well
Die Ausgabe des grep-Befehls sollte noch nach /dev/null umgeleitet werden:
if grep root /etc/passwd >/dev/null ...
$ cat scr if [ -f "$1" ]; then echo "$1: file" elif [ -d "$1" ]; then echo "$1: directory" else echo "$1: unknown" fi $ sh scr /etc/passwd /etc/passwd: file $ sh scr /etc /etc: directory $ sh scr /dev/null /dev/null: unknown
$ cat scr case $0 in /*) echo $0: absoluter Pfad ;; *) echo $0: relativer Pfad ;; esac $ $ sh scr scr: relativer Pfad $ ./scr ./scr: relativer Pfad $ `pwd`/scr /tmp/scr: absoluter Pfad
$ cat scr for i in /etc/rc*.d do cd $i echo $i: `ls | wc -l` done $ sh scr /etc/rc0.d: 30 /etc/rc1.d: 28 /etc/rc2.d: 42 /etc/rc3.d: 8 /etc/rcS.d: 40
Ohne Angabe von "in list" werden die auf der Befehlszeile angegebenen Parameter ($1, ...) iteriert:
$ cat scr for i do echo $i done $ sh scr a b c a b c
Beispiel: Parsen von Optionen und Argumenten
$ cat myls #!/bin/sh long=no # Option parsing: while [ $# != 0 ] do case $1 in -l) long=yes ;; --) # Ab hier keine Optionen mehr shift break ;; -*) echo Unbekannte Option $1 exit 1 ;; *) # Ende Option Parsing break ;; esac shift done # Argumente verarbeiten: while [ $# != 0 ] do if [ "$long" = yes ] ; then ls -l -- "$1" else ls -- "$1" fi shift done $ $ sh myls /etc/group /etc/group $ $ sh myls -l /etc/group -rw-r--r-- 1 root sys 278 Jan 3 2001 /etc/group $ $ sh myls -- -X -rw-r--r-- 1 feyrer bedienst 0 Apr 26 2006 -X
Parameter werden in den positionalen Argumenten $1, ... übergeben, $#, $@ und $* sind entsprechend gesetzt.
Beispiel 1: "dir"-Befehl für interaktive Shells
$ dir() > { > ls -la "$@" > } $ cd /tmp $ dir total 306 drwxrwxrwt 8 root sys 691 Nov 26 02:33 . drwxr-xr-x 25 root root 1024 Nov 19 08:50 .. drwxrwxr-x 2 root root 104 Nov 19 08:51 .X11-pipe drwxrwxr-x 2 root root 104 Nov 19 08:51 .X11-unix drwxrwxrwx 2 root nobody 69 Nov 20 00:14 .removable ... $ $ dir /etc/passwd -r--r--r-- 1 root sys 459 Nov 20 23:06 /etc/passwd
Beispiel 2: Aufruf von "myls" (s.o.) auch ohne Argumente
#!/bin/sh # Variablen sind global bekannt! long=no # Hilfsfunktion, ruft ls(1) mit/ohne Argument auf # wenn Variable 'long' gesetzt ist => ls -l do_ls1() { if [ "$long" = yes ] ; then lsargs=-l else lsargs= fi ls $lsargs -- "$1" } # Option parsing: ... # Argumente verarbeiten: if [ $# != 0 ] then while [ $# != 0 ] do do_ls1 "$1" shift done else do_ls1 . fiBeispiel 3: Geschwindigkeitsvergleich
$ cat myls_benchmark #!/bin/sh limit=1000 myecho_fn() { echo "$@" } echo Leere Schleife: i=0 date time while [ $i -lt $limit ] ; do i=`expr $i + 1` done date echo "" echo Shell-Funktion: i=0 date time while [ $i -lt $limit ] ; do i=`expr $i + 1` myecho_fn hallo welt >/dev/null done date echo "" echo Shell-Script: i=0 date time while [ $i -lt $limit ] ; do i=`expr $i + 1` ./myecho_scr hallo welt >/dev/null done date echo "" $ $ cat myecho_scr #!/bin/sh echo "$@" $ $ sh myecho_benchmark Leere Schleife: Mi Apr 27 12:28:48 CEST 2005 real 0m7.727s user 0m0.714s sys 0m2.030s Mi Apr 27 12:28:55 CEST 2005 Shell-Funktion: Mi Apr 27 12:28:55 CEST 2005 real 0m7.812s user 0m0.808s sys 0m1.879s Mi Apr 27 12:29:03 CEST 2005 Shell-Script: Mi Apr 27 12:29:03 CEST 2005 real 0m18.001s user 0m2.200s sys 0m4.425s Mi Apr 27 12:29:21 CEST 2005
rfhpc8317% time sh -c 'count=0; while [ $count -lt 1000 ]; do \ echo $count ; count=`expr $count + 1` ; done' > /dev/null 2.33u 8.59s 0:15.08 72.4% rfhpc8317% time sh -c 'count=0; while [ $count -lt 1000 ]; do \ echo $count ; pwd; count=`expr $count + 1` ; done' > /dev/null 2.31u 9.01s 0:15.23 74.3% rfhpc8317% time sh -c 'count=0; while [ $count -lt 1000 ]; do \ echo $count ; /bin/pwd; count=`expr $count + 1` ; done' > /dev/null 4.16u 16.58s 0:29.15 71.1%
Beispiel:
$ pwd /net/rfhs8012/home3/bedienst/feyrer $ $ owd=`pwd` $ cd /tmp $ pwd /tmp $ cd $owd $ pwd /net/rfhs8012/home3/bedienst/feyrer
Beispiel:
$ cat scr exit $1 $ sh scr 17 $ echo $? 17
Beispiel:
$ echo $$ 9832 $ sh $ echo $$ 9853 $ exec date Mon Nov 26 02:55:42 MET 2001 $ echo $$ 9832 $
Beispiel:
$ echo $$ 9832 $ ( echo $$ ) 9832 # Gleiche PID - keine fork() $ $ echo $SHELL /soft/bin/tcsh $ ( SHELL=foo ; echo $SHELL ) foo $ echo $SHELL /soft/bin/tcsh # SHELL nicht verändert $ $ pwd /net/rfhs8012/home3/bedienst/feyrer $ ( cd /tmp ; pwd ) /tmp $ pwd /net/rfhs8012/home3/bedienst/feyrer $ $ ( date ; ls /tmp ) >x $ cat x Thu Apr 15 12:24:55 CEST 2004 kde-feyrer ksmHUaafb ksocket-feyrer mcop-feyrer uscreens $ cd quelle $ tar -cf - . \ > | ( cd ziel ; tar -xf - )
$ cat scr echo Eingabe: \\c # SysV; BSD: echo -n Eingabe: read x echo Ihre Eingabe: $x $ sh scr Eingabe: test Ihre Eingabe: test $ cat scr #!/bin/sh PATH=/usr/xpg4/bin:${PATH} # besserer tail(1) auf Solaris sum=0; ls -l \ | tail -n +2 \ | while read line do set -- $line sum=`expr $sum + $5` done echo Disk usage: $sum bytes rfhpc8317% sh scr Disk usage: 0 bytes rfhpc8317% /usr/xpg4/bin/sh scr Disk usage: 2927254 bytes rfhpc8317% bash scr Disk usage: 0 bytesDer 'tail'-Befehl dient zum Überspringen der "total"-Zeile am Anfang. Die Unterschiede der Ausgabe ergeben sich durch unterschiedliche Ansichten in welcher Umgebung die Befehle in Pipelines ausgeführt werden: 2.12 "Shell Execution Environment" des IEEE Std 1003.1 (POSIX), 2004 Edition legt fest dass ``each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment.''. Eine Mögliche Loesung ist, while- und echo-Befehl zusammen in eine eigene Subshell "(...)" am Ende der Pipeline zu setzen.
Beispiel:
$ cat scr echo "Variable: \c" ; read var echo "Wert: \c" ; read val eval "alt=\$$var" ; echo Alter Wert von $var: $alt eval "$var=$val" eval "neu=\$$var" ; echo Neuer Wert von $var: $neu $ sh scr Variable: SHELL Wert: test Alter Wert von SHELL: /soft/bin/tcsh Neuer Wert von SHELL: test
Beispiel:
$ cat scr foo=bar $ echo $foo $ sh scr $ echo $foo $ . ./scr $ echo $foo barAbhängig von der Implementierung ist, ob das angegebene Script im aktuellen Verzeichnis (relativ zu ".") oder im Suchpfad gesucht wird. Ist ersteres beabsichtigt, so ist dies explizit - wie im Beispiel - anzugeben!
Beispiel:
$ cat scr sleep 5 & date wait date $ sh scr Mon Nov 26 03:19:39 MET 2001 Mon Nov 26 03:19:44 MET 2001 $
$ time sleep 5 real 5.0 user 0.0 sys 0.0 $ time date Mon Nov 26 03:21:54 MET 2001 real 0.0 user 0.0 sys 0.0 $
which -> (t)csh builtin oder externes Programm
rfhpc8317% which date /bin/date rfhpc8317% which time time: shell built-in command. rfhpc8317% which which which: shell built-in command. rfhpc8317% which type /bin/typetype -> (ba)sh builtin
rfhpc8317% sh $ which date /bin/date $ which time /bin/time $ which which /bin/which $ $ $ type date date is /bin/date $ type time time is /bin/time $ type which which is hashed (/bin/which) $ type type type is a shell builtin $ type time time is /bin/time $ time date Tue Apr 27 12:09:20 CEST 2004 real 0.0 user 0.0 sys 0.0 $ type time time is hashed (/bin/time)Hinweis zur Optimierung:
rfhpc8317% which type /bin/type rfhpc8317% ls -li /bin/type 280 -r-xr-xr-x 17 root bin 134 Nov 4 2002 /bin/type rfhpc8317% find /bin/. -inum 280 | wc -l 17 rfhpc8317% cd /bin ; echo `find . -inum 280` ./alias ./bg ./cd ./command ./fc ./fg ./getopts ./hash ./jobs ./kill ./read ./test ./type ./ulimit ./umask ./unalias ./wait rfhpc8317% file /bin/type /bin/type: executable /bin/ksh script rfhpc8317% cat /bin/type #!/bin/ksh -p # #ident "@(#)alias.sh 1.2 00/02/15 SMI" # # Copyright (c) 1995 by Sun Microsystems, Inc. # cmd=`basename $0` $cmd "$@"Die Shell-Builtins werden mit Hilfe des ksh-Scripts gleichzeitig als externe Befehle angeboten, um sie Programmen ausserhalb der Shell (z.B. via system(3), exec(2)) zur Verfügung zu stellen.
rfhpc8317% cat /tmp/x #!/bin/sh trap 'echo INTERRUPT!' TERM INT echo "^C abgestellt" for i in 1 2 3 4 5 ; do echo ignoriert $i ; sleep 1 ; done echo "" trap TERM INT echo "^C angestellt" for i in 1 2 3 4 5 ; do echo unterbrechbar $i ; sleep 1 ; done rfhpc8317% sh /tmp/x ^C abgestellt ignoriert 1 ignoriert 2 ignoriert 3 ^CINTERRUPT! ignoriert 4 ^CINTERRUPT! ignoriert 5 ^C angestellt unterbrechbar 1 unterbrechbar 2 ^Crfhpc8317%