-
`?
Subject: How do I remove a file whose name begins with a "-" ? Date: Thu Mar 18 17:16:55 EST 1993Poiščite tak način imenovanja datoteke, da se ne začne s pomišljajem. Najpreprostejši odgovor je primer
rm ./-imedatoteke
(seveda predvidevamo, da je ,,-imedatoteke
`` v tem primeru v trenutnem
imeniku).
Ta način izogibanja dvoumnemu ,-
` na začetku imen deluje tudi pri
drugih ukazih.
Veliko ukazov, posebej tistih, ki so bili napisani z uporabo rutine
,,getopt(3)
`` za razčlembo argumentov, sprejme tudi argument
,,--
``, ki pomeni ,,to je zadnja izbira, vse po tem ni več
izbira``. Vaša različica rm
potemtakem morebiti razume tudi
rm -- -imedatoteke
Nekatere različice rm
, ki ne uporabljajo getopt()
, razumejo
podobno tudi en sam ,,-
``, torej lahko poskusite kar z ,,rm -
-imedatoteke
``.
Subject: How do I remove a file with funny characters in the filename ? Date: Thu Mar 18 17:16:55 EST 1993Če je ,,čuden znak`` znak ,
/
`, preskočite na zadnji del
odgovora. Če je čuden znak nekaj drugega, na primer presledek ali
kontrolni znak ali znak s prižganim osmim bitom (to so npr. slovenske
črke ,,蚞ȊŽ
``), nadaljujte z branjem.
Prvi klasični odgovor je uporaba ukaza na način
rm -i vzorec*ki*ustreza*le*datoteki*ki*jo*želite
Ukaz vpraša za vsako datoteko, ki ustreza vzorcu, če jo želite
odstraniti. Nasvet morda v vaši ukazni lupini ne bo deloval zaradi
znakov s prižganim osmim bitom, saj ga ukazna lupina lahko odreže.
Drugi klasični odgovor je
rm -ri .
ki vas za vsako datoteko v trenutnem imeniku vpraša, ali naj jo odstrani.
V angleškem okolju odgovorite z ,y
` pri problematični datoteki in
z ,n
` pri vseh ostalih datotekah. Žal to ne deluje pri veliko
različicah rm
. Hkrati se bo ukaz izvedel za vse datoteke na vseh
podimenikih trenutnega imenika, torej boste morda začasno hoteli te
imenike narediti nedostopne z ,,chmod a-x
``, da vas ne bodo
motili.
Vselej globoko vdihnite in razmislite, kaj počnete, ter dvakrat
preverite, kaj ste zapisali v ukazni vrstici, kadar uporabljate
zastavico ,,-r
`` ukaza rm
ali znaka *
ali ?
(angl. wildcard).
Tretji klasični odgovor je
find . -type f ... -ok rm '{}' \;
kjer je ,,...
`` skupina oznak, ki enolično določa ime datoteke.
Ena od možnosti je, da za problematično datoteko poiščete njeno
številko inode (z uporabo ukaza ,,ls -i .
``) in potem
uporabite
find . -inum 12345 -ok rm '{}' \;
ali
find . -inum 12345 -ok mv '{}' novo-ime-datoteke \;
,,-ok
`` je varnostno preverjanje - program vas bo vprašal za
potrditev ukaza, preden ga bo izvedel. Spraševanju se lahko izognete
z uporabo ,,-exec
``, če radi živite nevarno, ali če domnevate, da
ime datoteke vsebuje zaporedje čudnih znakov, ki vam bodo ob izpisu
zmešali zaslon.
Kaj, če ime datoteke vsebuje znak ,/
`?
Te datoteke so res posebni primeri in jih lahko ustvari le hroščata koda v jedru (tipično jih naredijo implementacije NFS, ki ne počistijo neveljavnih znakov iz imen datotek na oddaljenih strojih). Najprej poskušajte natanko razumeti, zakaj je ta problem tako izjemen.
Spomnite se, da so imeniki v Unixu preprosto pari imen datotek in številk inode. Imenik tipično vsebuje podobno informacijo:
ime datoteke inode
datoteka1 12345
datoteka2.c 12349
datoteka3 12347
Teoretično sta ,/
` in ,\0
` le dva znaka, ki se ne
moreta pojaviti v imenu datoteke - znak ,/
` zato, ker se
uporablja za ločevanje imenikov in datotek, in znak ,\0
`
zato, ker končuje ime datoteke.
Žal nekatere izvedbe omrežnega datotečnega sistema NFS prešerno ustvarjajo datoteke z vključenimi nagibnicami kot odgovor na zahteve oddaljenih strojev. Na primer, to se lahko zgodi, ko se nekdo na Macu ali drugem ne-Unixu odloči narediti oddaljeno datoteko NFS na vašem Unixu, z datumom v imenu datoteke. Vaš imenik na Unixu ima potem v sebi tole:
ime datoteke inode
91/02/07 12357
Takšne datoteke ne bo pobrisalo nobeno zgoraj opisano čaranje z
ukazoma find
in rm
, saj morata tako tadva pripomočka kot
tudi vsi drugi programi na Unixu razumeti znak ,/
` na
običajen način.
Vsak običajen program bo želel narediti unlink("91/02/07")
,
kar jedro razume kot ,,pobriši datoteko 07
v podimeniku 02
imenika 91
``, toda to ni tisto, kar hočemo - imamo datoteko
imenovano ,,91/02/07
`` v trenutnem imeniku. To je komaj
zaznavna, a ključna razlika.
Kaj lahko naredite v tem primeru? Najprej se poskusite vrniti na Maca, ki je ustvaril ta nevšečni vnos, in skušajte prepričati Maca in vaš lokalni strežnik NFS, da datoteko preimenujeta v nekaj, kar ne vsebuje nagibnic.
Če to ne deluje ali morda ni izvedljivo, boste potrebovali pomoč
vašega sistemskega upravitelja, ki bo moral poskusiti kaj od
naslednjega. Uporabite ,,ls -i
``, da boste izvedeli številko
inode nesrečne datoteke, potem odklopite datotečni sistem (z
umount
), uporabite ,,clri
`` za izbris inodea, in popravite
datotečni sistem s ,,fsck
`` in s stisnjenimi pestmi. Postopek
uniči podatke o datoteki. Če jih želite obdržati, lahko poskusite:
ls -id
`` ,
da dobite njegovo številko inumber,clri
`` na imeniku, ki vsebuje sporno datoteko,fsck
``.fsck
``);lost+found
`` v imenik
s primernejšim imenom.fsdb
``, če ga imate.
Subject: How do I get a recursive directory listing? Date: Thu Mar 18 17:16:55 EST 1993
Nekaj od tega bo naredilo to, kar želite:
ls -R (vse različice ,ls` nimajo ,-R`)
find . -print (to mora delovati povsod)
du -a . (pokaže ime in velikost)
Če iščete vzorec z jokerji (angl. wildcard), ki bo ustrezal
vsem datotekam ,,.c
`` v tem imeniku in pod njim, ga ne
boste našli, pač pa lahko uporabite:
% nek-ukaz `find . -name '*.c' -print`
,,find
`` je zmogljiv program. Poučite se o njem.
Subject: How do I get the current directory into my prompt? Date: Thu Mar 18 17:16:55 EST 1993
Odvisno od tega, katero ukazno lupino uporabljate. V nekaterih ukaznih lupinah je to preprosto, v drugih pa težko ali celo nemogoče.
csh
):
Vstavite tole v svojo datoteko
.cshrc
- preuredite spremenljivko pozivnika po svojem
okusu.
alias setprompt 'set prompt="${cwd}% "'
setprompt # nastavitev uvodnega pozivnika
alias cd 'chdir \!* && setprompt'
Če uporabljate pushd
in popd
, boste potrebovali
tudi:
alias pushd 'pushd \!* && setprompt'
alias popd 'popd \!* && setprompt'
Nekatere lupine csh
nimajo spremenljivke $cwd
- namesto tega lahko uporabite `pwd`
.
Če želite dobiti v vaš pozivnik le zadnjo komponento vašega
trenutnega imenik (,,mail%
`` namesto
,,/usr/spool/mail%
``), lahko uporabite
alias setprompt 'set prompt="$cwd:t% "'
Pomen operatorjev &&
in ||
v nekaterih starejših lupinah
csh
je zamenjan. Poskusite:
false && echo napaka
Če izpiše ,,napaka
``, morate zamenjati &&
in ||
(in dobiti boljšo različico csh
.)
sh
):
Če imate novejšo različico Bournove ukazne lupine (SVR2 ali novejšo),
lahko uporabite za izdelavo svojega ukaza funkcijo lupine,
denimo ,,xcd
``:
xcd() { cd $* ; PS1="`pwd` $ "; }
Če imate starejšo Bournovo ukazno lupino, je to zapleteno,
a mogoče. Dodajte v vašo datoteko .profile
:
LOGIN_SHELL=$$ export LOGIN_SHELL
CMDFILE=/tmp/cd.$$ export CMDFILE
# 16 je SIGURG, izberite signal, ki se navadno ne uporablja
PROMPTSIG=16 export PROMPTSIG
trap '. $CMDFILE' $PROMPTSIG
in potem postavite ta izvedljivi skript (brez zamikanja!),
recimo mu ,,xcd
`` nekam v vašo pot (PATH
).
: xcd directory - change directory and set prompt
: by signalling the login shell to read a command file
cat >${CMDFILE?"not set"} <<EOF
cd $1
PS1="\`pwd\`$ "
EOF
kill -${PROMPTSIG?"not set"} ${LOGIN_SHELL?"not set"}
Zdaj spreminjajte imeniku z ukazom ,,xcd /nek/imenik
``.
ksh
):
Vstavite to v vašo datoteko .profile
:
PS1='$PWD $ '
Če želite le zadnjo komponento imenika, uporabite
PS1='${PWD##*/} $ '
tcsh
)
Tcsh
je popularna izboljšana različica csh
z nekaterimi dodatnimi vgrajenimi spremenljivkami (in
veliko drugih zmožnosti):
%~ trenutni imenik, uporablja ~ za $HOME
%/ polna pot trenutnega imenika
%c ali %. končna komponenta trenutnega imenika
tako, da lahko preprosto ukažete
set prompt='%~ '
Simbol \w
v $PS1
daje polno ime poti trenutnega
imenika, z uporabo ~
za $HOME
; \W
daje
osnovno ime (angl. basename) trenutnega imenika. Torej lahko
poleg zgornjih rešitev za sh
in ksh
uporabite tudi
PS1='\w $ '
ali
PS1='\W $ '
Subject: How do I read characters from the terminal in a shell script? Date: Thu Mar 18 17:16:55 EST 1993
V sh
, uporabite read
. Navadno se uporabi podobna zanka:
while read vrstica
do
echo $vrstica
...
done
V csh
uporabite $<
, kot tukaj:
while ( 1 )
set vrstica = "$<"
if ( "$vrstica" == "" ) break
...
end
Žal se v csh
ne da razločevati med prazno vrstico in
koncem datoteke.
Če uporabljate sh
in bi radi prebrali en sam znak
s terminala, lahko poskusite nekaj podobnega:
echo -n "Vstavite znak: "
stty cbreak # ali stty raw
beriznak=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
stty -cbreak
echo
echo "Hvala, da ste vtipkali $beriznak ."
*.foo
v *.bar
ali spremenim imena datotek v male črke?
Subject: How do I rename "*.foo" to "*.bar", or change file names to lowercase? Date: Thu Mar 18 17:16:55 EST 1993
Zakaj ne deluje ,,mv *.foo *.bar
``? Premislite, kako ukazna
lupina razvija jokerje (angl. wildcards). Niza ,,*.foo
`` in
,*.bar
`` se razvijeta, preden ukaz mv
sploh vidi argumente.
Odvisno od vaše ukazne lupine lahko to spodleti na več načinov.
CSH
izpiše ,,No match.
``, ker ne najde ,,*.bar
``.
SH
izvede ,,mv a.foo b.foo c.foo *.bar
``, kar bo uspelo
le, če imate en sam imenik, ki ustreza ,,*.bar
``, kar je zelo
neverjetno in skoraj zagotovo ni tisto, kar ste imeli v mislih.
Odvisno od vaše ukazne lupine lahko to storite z zanko, v kateri
poženete ,,mv
`` na vsaki posamezni datoteki. Če ima vaš sistem
,,basename
``, lahko uporabite:
foreach f ( *.foo )
set base=`basename $f .foo`
mv $f $base.bar
end
for f in *.foo; do
base=`basename $f .foo`
mv $f $base.bar
done
basename
`` uporabite vgrajene mehanizme, kot so:
foreach f ( *.foo )
mv $f $f:r.bar
end
for f in *.foo; do
mv $f ${f%foo}bar
done
basename
`` ali bi želeli preimenovati
foo.*
v bar.*
, lahko uporabite kar ,,sed
`` ali podobno
orodje, da predelate ime datoteke, a v splošnem je ideja zanke enaka.
S pripomočkom ,,sed
`` lahko spremenite imena datotek v ukaze za
mv
in pošljete ukaze za izvajanje lupini ,,sh
``. Poskusite:
ls -d *.foo | sed -e 's/.*/mv & &/' -e 's/foo$/bar/' | sh
Obstaja program Vladimirja Lanina, imenovan ,,mmv
``, ki opravi
preimenovanje datotek in je bil aprila 1990 objavljen v
comp.sources.unix (Volume 21,
issues 87 and 88). Omogoča vam uporabo na način
mmv '*.foo' '=1.bar'
V ukaznih lupinah zanke, podobne zgornjim, pomagajo pri zamenjavi imen
datotek iz velikih črk v male ali obratno. Velike črke v imenih
datotek prevedete v male takole:
foreach f ( * )
mv $f `echo $f | tr '[A-Z]' '[a-z]'`
end
for f in *; do
mv $f `echo $f | tr '[A-Z]' '[a-z]'`
done
typeset -l l
for f in *; do
l="$f"
mv $f $l
done
for f in *; do
g=`expr "xxx$f" : 'xxx\(.*\)' | tr '[A-Z]' '[a-z]'`
mv "$f" "$g"
done
Ukaz ,expr
` vedno izpiše ime datoteke, tudi, če je to
enako ,-n
`, ali, če vsebuje ubežna zaporedja za System V,
kakršno je ,\c
`.
Nekatere različice ukaza ,,tr
`` potrebujejo ,[
` in
,]
`, nekatere ju ne. V tem konkretnem primeru ju je
povsem neškodljivo vključiti. Različice ukaza tr
, ki
nočejo ,,[]
`` bodo primerno mislile, da bi
morale preslikati ,[
` v ,[
` in ,]
`
v ,]
`.
perl
``, lahko
ta skript Larryja Walla za preimenovanje datotek uporabite
zelo koristno. Uporabljate ga lahko za širok spekter sprememb
imen datotek.
#!/usr/bin/perl
#
# primeri uporabe skripta rename (avtor lwall):
# rename 's/\.orig$//' *.orig
# rename 'y/A-Z/a-z/ unless /^Make/' *
# rename '$_ .= ".bad"' *.f
# rename 'print "$_: "; s/foo/bar/ if <stdin> =~ /^y/i' *
$op = shift;
for (@ARGV) {
$was = $_;
eval $op;
die $@ if $@;
rename($was,$_) unless $was eq $_;
}
rsh gostitelj ukaz
`` [kakšno čudno sporočilo o napaki]?
Subject: Why do I get [some strange error message] when I "rsh host command" ? Date: Thu Mar 18 17:16:55 EST 1993(Govorimo o programu za oddaljeno ukazno lupino ,,
rsh
``, ki se
ponekod imenuje ,,remsh
`` ali ,,remote
``. Obstaja tudi
ukazna lupina z omejitvami, imenovana ,,rsh
``, kar pa je druga
stvar.)
Če vaš oddaljeni račun uporablja C-jevsko ukazno lupino (csh
), bo
oddaljeni gostitelj pognal csh
, da bi izvedel vaš ,ukaz
`, in
ukazna lupina bo prebrala vašo oddaljeno datoteko .cshrc
. Morda
ta .cshrc
vsebuje ,,stty
``, ,,biff
`` ali kakšen drug
ukaz, ki ni primeren za neinteraktivno ukazno lupino. Nepričakovan
izhod ali sporočilo o napaki pri teh ukazih lahko zapleteta vašo
lupino rsh
na čudne načine.
Tukaj je primer. Denimo, da imate v vaši datoteki .cshrc
tole:
stty erase ^H
biff y
Dobili boste čudna sporočila, kot je tole:
% rsh nek-stroj date
stty: : Can't assign requested address
Where are you?
Tue Oct 1 09:24:45 EST 1991
Podobne napake lahko dobite, če izvajate določena opravila pripomočkov
,,at
`` ali ,,cron
``, ki prav tako bereta vašo datoteko
.cshrc
.
Na srečo je popravek preprost. Zelo verjetno je v vaši datoteki
,,.cshrc
`` na kupe operacij, ki jih preprosto ni vredno
izvajati drugje kot v interaktivnih ukaznih lupinah (npr. ,,set
history=N
``). Tedaj jih postavite v pogojni blok v vaši
,,.cshrc
`` z
if ( $?prompt ) then
operacije...
endif
Ker v neinteraktivnih ukaznih lupinah spremenljivka ,,prompt
`` ni
nastavljena, bodo sporne operacije izvedene le v interaktivnih ukaznih
lupinah.
Morda boste želeli premakniti nekatere ukaze v vaš prijavni skript
.login
. Če se morajo ti ukazi izvesti le ob vaši prijavi na
sistem (iskanje nove pošte, neprebranih novičarskih sporočil in tako
naprej), jih je bolje imeti v datoteki .login
.
Subject: How do I ... and have that change affect my current shell? Date: Thu Mar 18 17:16:55 EST 1993
V splošnem tega ne morete storiti, vsaj ne brez posebnih priprav. Ko nek proces ustvari svoj podproces, ta podeduje kopijo spremenljivk svojega očeta (vključno s trenutnim imenikom). Otrok lahko spremeni podedovane vrednosti, kolikor hoče, vendar te spremembe ne bodo prizadele starševskega okolja, saj otrok spreminja le svojo kopijo originalnih podatkov.
Možne so nekatere posebne priprave. Vaš otroški proces lahko izpiše spremenjene spremenljivke, če je oče vnaprej pripravljen prebrati ta izhod in ga razumeti tako, da ustrezno nastavi svoje lastne spremenljivke.
Ukazne lupine lahko izvajajo skripte tudi v okolju osnovnega procesa, namesto v okolju podprocesa, in tedaj bodo spremembe prizadele tudi osnovno ukazno lupino.
Na primer, če je vašemu skriptu za csh
ime ,,mojskript
`` in
ta vsebuje:
cd /zelo/dolga/pot setenv PATH /nekaj:/nekaj-drugega
ali če imate podoben skript za Bournovo ali Kornovo ukazno lupino
cd /zelo/dolga/pot PATH=/nekaj:/nekaj-drugega export PATH
in poskušate pognati ,,mojskript
`` v vaši ukazni lupini, se bo
vaša ukazna lupina razvejila in pognala lupinski skript kot svoj
podproces, v katerem bo izvedla ukaz ,,cd
``. Ta bo spremenil
svoj trenutni imenik, in z ukazom ,,setenv
`` spremenil
svoje okolje, vendar nobeden od ukazov ne bo vplival na trenutni
imenik ukazne lupine, v katerem tipkate (vaše prijavne ukazne lupine,
denimo).
Če želite prepričati vašo prijavno ukazno lupino, da požene skript v
trenutnem procesu (brez razvejevanja), morate uporabiti ukaz
,,.
`` (za Bournovo ali Kornovo lupino) ali ukaz ,,source
``
(za lupino C). Se pravi, v Bournovih ali Kornovih ukaznih
lupinah napišete
. mojaskripta
v lupini C pa
source myscript
Če je vse, kar poskušate storiti, le sprememba imenika ali nastavitev spremenljivke okolja, bo verjetno najlažje, da uporabite vzdevek (angl. alias) v lupini C ali funkcijo v Bournovi/Kornovi ukazni lupini. Glejte razdelek ,,Kako lahko dobim trenutni imenik v moj pozivnik?`` za nekaj primerov.
Veliko bolj podroben odgovor je pripravil Thomas Michanek
<xtm@telelogic.se
>. Dobite ga lahko po
FTP-ju z naslova
ftp://ftp.wg.omron.co.jp/pub/unix-faq/docs/script-vs-env.
csh
ločeno preusmerim stdout in stderr?
Subject: How do I redirect stdout and stderr separately in csh? From: msb@sq.com (Mark Brader) Date: Mon, 26 Oct 1992 20:15:00 -0500
V csh
lahko preusmerite stdout z ,,>
`` ter hkrati stdout in
stderr z ,,>&
``, a ni neposrednega načina
le za preusmeritev stderr. Najboljše, kar lahko naredite, je
( ukaz >datoteka_za_stdout ) >&datoteka_za_stderr
ki požene ,,ukaz
`` v ukazni podlupini; stdout se preusmeri
znotraj podlupine v datoteko ,,datoteka_za_stdout
``, stdout
in stderr podlupine pa se skupaj preusmerita v datoteko
,,datoteka_za_stderr
``, toda na tej točki je stdout že
preusmerjen, tako da v datoteki ,,datoteka_za_stderr
`` konča
pravzaprav le stderr.
Če želite le preprečiti preusmeritev stdout,
tedaj to za vas stori sh
:
sh -c 'ukaz 2>datoteka_za_stderr'
.cshrc
ugotovim, ali sem prijavna ukazna lupina?
Subject: How do I tell inside .cshrc if I'm a login shell? Date: Thu Mar 18 17:16:55 EST 1993
Ko ljudje govorijo tako, pravzaprav s tem mislijo nekaj od naslednjega:
Morda lahko ugotovite, ali je vaša ukazna lupina resnično prijavna
lupina (se pravi, bo prebrala ,,.login
`` potem, ko bo opravila
z ,,.cshrc
``) tako, da zapravljate čas s ,,ps
`` in ,,$$
``.
Prijavne lupine imajo v splošnem imena, ki se začnejo s ,-
`.
Če vas v resnici zanimata drugi dve vprašanji, je tukaj način organizacije
vaše datoteke .cshrc
, da to izveste.
if (! $?CSHLEVEL) then # # To je "najvišjenivojska" ukazna lupina, # morda prijavna lupina, morda lupina, pognana z # 'rsh stroj nek-ukaz' # Tukaj moramo nastaviti pot PATH in vse drugo, # kar želimo imeti v vsaki od naših ukaznih lupin. # setenv CSHLEVEL 0 set home = ~username # za vsak slučaj source ~/.env # nastavimo okolje else # # Ta lupina je otrok ene od drugih ukaznih lupin, zato # nam ni treba ponovno nastaviti vseh spremenljivk okolja. # set tmp = $CSHLEVEL @ tmp++ setenv CSHLEVEL $tmp endif # Izhod iz .cshrc, če ni interaktivna, npr. pod rsh. if (! $?prompt) exit # Tukaj smemo nastaviti pozivnik ali vzdevke, ki bi bili # uporabni le za interaktivne ukazne lupine. source ~/.aliases
.
`` in ,,..
``?
Subject: How do I construct a ... matches all files except "." and ".." ? Date: Thu Mar 18 17:16:55 EST 1993
In vi ste mislili, da bo to preprosto ...
*
Ustreza vsem datotekam, ki se ne začenjajo z ,,.
``;
.*
Ustreza vsem datotekam, ki se začenjajo z ,,.
``, toda
to vključuje posebna vnosa ,,.
`` in ,,..
``, ki
ju pogosto ne želite;
.[!.]*
(Le novejše ukazne lupine; nekatere lupine uporabljajo ,,^
``
namesto ,,!
``; ukazne lupine POSIX-a morajo sprejeti
,,!
``, a lahko sprejmejo tudi ,,^
``; prenosljive
aplikacije ne bi smele uporabljati necitiranega ,,^
``
takoj za ,,[
``.)
Ustreza vsem datotekam, ki se začnejo z ,,.
`` in jim
sledi ne-,,.
``; žal bo to spregledalo ,,..foo
``;
.??*
Ustreza datotekam, ki se začnejo z ,,.
`` in so dolge
vsaj tri znake. To se prikupno izogne ,,.
`` in ,,..
``,
a tudi spregleda ,,.a
``.
.
`` in
,,..
``, morate uporabiti 3 vzorce (če nimate imen datotek, kot je
,,.a
``, lahko izpustite prvega):
.[!.]* .??* *
Alternativno lahko zaposlite zunanji program ali dva in uporabite
substitucijo znotraj narekovaja (angl. backquote substitution).
To (ali ,ls -A
` na nekaterih različicah Unixa) je precej
dobro:
`ls -a | sed -e '/^\.$/d' -e '/^\.\.$/d'`
a tudi to bo zamočilo pri datotekah z znaki za novo vrsto,
znaki IFS ali jokerjih v njihovih imenih.
V ksh
lahko uporabite:
.!(.|) *
Subject: How do I find the last argument in a Bourne shell script? Date: Thu Mar 18 17:16:55 EST 1993
Odgovor sta prispevala:
@mikros.systemware.de
:martin@mwtech.uucp
>maart@nat.vu.nl
>
eval zadnji=\${$#}
V ukaznih lupinah, združljivih s standardom POSIX, to deluje za vsako število argumentov. Vselej deluje tudi:
for zadnji
do
:
done
Primer se posploši takole:
for i
do
predpredzadnji=$predzadnji
predzadnji=$zadnji
zadnji=$i
done
Zdaj pa denimo, da želite odstraniti zadnji argument iz seznama
ali obrniti seznam argumentov ali za vsak N dostopati
neposredno do N-tega argumenta. Tukaj navajamo osnovni primer,
kako to storiti, in uporabimo le vgrajene konstrukte ukazne lupine, ne
da bi ustvarjali dodatne podprocese:
t0= u0= ostanek='1 2 3 4 5 6 7 8 9' argv=
for h in '' $ostanek
do
for t in "$t0" $ostanek
do
for u in $u0 $ostanek
do
case $# in
0)
break 3
esac
eval argv$h$t$u=\$1
argv="$argv \"\$argv$h$t$u\"" # (1)
shift
done
u0=0
done
t0=0
done
# zdaj obnovimo argumente
eval set x "$argv" # (2)
shift
Ta primer deluje za prvih 999 argumentov. Dovolj? Dobro poglejte
vrstici, označeni z (1) in (2) in se prepričajte, da se originalni
argumenti res obnovijo, ne glede na to, katere čudne znake vsebujejo!
N-ti argument lahko zdaj poiščete takole:
eval argN=\$argv$N
Če želite obrniti argumente, morate spremeniti vrstico, označeno z (1),
argv="\"\$argv$h$t$u\" $argv"
Kako odstranite zadnji argument, vam prepuščamo za nalogo.
Če dovoljujete tudi podprocese, ki morda izvajajo nevgrajene
ukaze, lahko spremenljivke ,argvN
` določite
preprosteje:
N=1
for i
do
eval argv$N=\$i
N=`expr $N + 1`
done
Za obračanje argumentov obstaja še preprostejša metoda, ki niti ne
ustvarja podprocesov. Ta pristop lahko uporabite tudi, ko želite
pobrisati npr. zadnji argument, a v tem primeru se ne morete več
sklicevati neposredno na N-ti argument, saj so spremenljivke
,argvN
` nastavljene v obratnem vrstnem redu:
argv=
for i
do
eval argv$#=\$i
argv="\"\$argv$#\" $argv"
shift
done
eval set x "$argv"
shift
.
` v svoji poti $PATH
?
Subject: What's wrong with having '.' in your $PATH ? Date: Thu Mar 18 17:16:55 EST 1993
Malce ozadja: spremenljivka okolja PATH
je seznam imenikov,
ločenih z dvopičji. Ko vpišete ukaz brez jasno določene poti
(npr. napišete ,,ls
`` in ne ,,/bin/ls
``), vaša ukazna
lupina išče izvedljivo datoteko s tem imenom po vseh imenikih,
naštetih v seznamu PATH
, lepo po vrsti, in izvede prvi program,
ki ga najde.
Eden od imenikov v seznamu PATH
je lahko tudi trenutni imenik
,,.
``. Kot znak za trenutni imenik v seznamu PATH
lahko
uporabite tudi prazni imenik. Ta dva načina označevanja sta
ekvivalentna:
csh
:
setenv PATH :/usr/ucb:/bin:/usr/bin
setenv PATH .:/usr/ucb:/bin:/usr/bin
sh
ali ksh
:
PATH=:/usr/ucb:/bin:/usr/bin export PATH
PATH=.:/usr/ucb:/bin:/usr/bin export PATH
.
`` nekje v PATH
je udobno - za poganjanje
programov v trenutnem imeniku lahko namesto ,,./a.out
``
napišete ,,a.out
``. A obstaja kavelj.
Premislite, kaj se zgodi v primeru, da je ,,.
`` prvi vnos v
seznamu PATH
. Denimo, da je vaš trenutni imenik javno dostopen
za pisanje, na primer ,,/tmp
``. Če je tam slučajno program,
imenovan ,,/tmp/ls
``, ki ga je tam pustil kak drug uporabnik,
ter vi napišete ,,ls
`` (namesto, da bi, seveda, pognali običajen
program ,,/bin/ls
``), bo vaša ukazna lupina pognala
,,./ls
``, program tistega drugega uporabnika. Odveč je
napisati, da vas lahko poganjanje neznanega programa, kot je ta,
nadvse preseneti.
Bolje je postaviti oznako za trenutni imenik ,,.
`` na konec PATH
:
setenv PATH /usr/ucb:/bin:/usr/bin:.
Če ste zdaj v imeniku /tmp
in napišete ,,ls
``, bo ukazna
lupina najprej preiskala /usr/ucb
, /bin
in
/usr/bin
za program, imenovan ,,ls
``, preden bo
pogledala v ,,.
``, kar daje manj možnosti, da bi nehote pognali
program ,,ls
`` drugega uporabnika. Tudi to ni povsem varno - če
ste neroden strojepisec in nekega dne napišete ,,sl -l
``
namesto ,,ls -l
``, tvegate, da boste pognali
,,./sl
``, če ta obstaja. Kak ,,bister`` programer lahko
računa na pogoste tipkarske napake in pušča programe s takimi imeni
raztrosene po javnih imenikih. Pazite!
Veliko izkušenih uporabnikov Unixa shaja povsem dobro, ne da bi sploh
imeli ,,.
`` vključen v PATH
:
setenv PATH /usr/ucb:/bin:/usr/bin
Če naredite to, boste morali za zagon programov vselej pisati
,,./program
`` namesto program
, a povečanje varnosti je
verjetno vredno tega truda.
Subject: How do I ring the terminal bell during a shell script? From: uwe@mpi-sb.mpg.de (Uwe Waldmann) Date: Fri, 30 Apr 93 16:33:00 +0200
Odgovor je odvisen od različice vašega Unixa (ali raje od vrste
programa ,,echo
``, ki je na voljo na vašem stroju).
BSD-jevski ,,echo
`` uporablja izbiro ,,-n
`` za preprečitev
izpisa končnega znaka za konec vrstice (angl. final newline) in ne
razume osmiškega zapisa \nnn. Ukaz se torej glasi
echo -n '^G'
kjer ^G
pomeni dobesedni znak BEL (vstavite ga lahko
v Emacsu s kombinacijo ,,Ctrl-Q Ctrl-G`` ali v vi
z uporabo
,,Ctrl-V Ctrl-G``).
Na Unixih SysV ukaz ,,echo
`` razume zapis \nnn in uporablja
\c
za preprečitev izpisa končnega znaka za konec vrstice,
torej je odgovor:
echo '\007\c'
talk
`` za pogovor s prijateljem na stroju X?
Subject: Why can't I use "talk" to talk with my friend on machine X? From: tmatimar@isgtec.com (Ted Timar) Date: Thu Mar 18 17:16:55 EST 1993Unix ima tri razširjene programe ,,
talk
`` in nobeden od njih se
ne zna pogovoriti z ostalima. ,,Stari`` talk
vključuje prva dva
tipa. Ta različica (pogosto imenovana otalk
) pri pogovoru med
stroji ni upoštevala vrstnega reda bytov. Zaradi tega se različica
otalk
za Vax ni mogla pogovarjati z različico otalk
za Sun.
Te različice talk
-a uporabljajo vrata 517.
Okoli leta 1987 se je večina proizvajalcev (razen Suna, ki je
potreboval šest let več od svojih tekmecev) dogovorila o standardu za
novi program talk
(pogosto imenovan ntalk
), ki ve za omrežni
vrstni red bytov. Ta talk
deluje med vsemi stroji, ki ga
podpirajo. Ta različica talk
-a uporablja vrata 518.
Dandanes obstaja nekaj programov talk
, ki hkrati govorijo
ntalk
in eno od različic otalk
. Najbolj znan med njimi se
imenuje ,,ytalk
``.
Subject: Why does calendar produce the wrong output? From: tmatimar@isgtec.com (Ted Timar) Date: Thu Sep 8 09:45:46 EDT 1994Pogosto ljudje ugotovijo, da izhod Unixovega koledarskega programa ,,
cal
`` ne ustreza njihovim pričakovanjem.
Koledar za september 1752 je zelo čuden:
September 1752
S M Tu W Th F S
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
To je mesec, v katerem so ZDA (pravzaprav celoten Britanski Imperij)
zamenjale julijanski koledar z gregorijanskim.
Drug pogost problem, ki ga imajo ljudje s koledarskim programom, je,
da mu podajajo argumente kot je ,,cal 9 94
``. To izpiše
koledar za september leta 94, ne pa leta 1994.