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 .
fi
Beispiel 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 bytes
Der '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%