Bash voorziet in een andere omgevingsvariabele genaamd PROMPT_COMMAND. De inhoud van deze variabele wordt uitgevoerd als een regulier Bash-commando net voordat Bash een prompt toont.
[21:55:01][giles@nikola:~] PS1="[\u@\h:\w]\$ "
[giles@nikola:~] PROMPT_COMMAND="date +%H%M"
2155
[giles@nikola:~] d
bin mail
2156
[giles@nikola:~]
Wat hierboven gebeurde is dat ik PS1 zo wijzigde dat de escape sequence
\t
er niet langer in was opgenomen, dus de tijd maakte niet langer
onderdeel uit van de prompt. Toen gebruikte ik date +%H%M
om de
tijd in een beter formaat te tonen. Maar het verschijnt op een andere regel
dan de prompt. Dit in orde brengend met echo -n ...
zoals hieronder
getoond werkt met Bash 2.0+, maar schijnt niet met Bash 1.14.7 te werken.
Blijkbaar wordt de prompt op een andere manier getekend. De volgende
methode resulteert in een overlappende tekst.
2156
[giles@nikola:~] PROMPT_COMMAND="echo -n [$(date +%H%M)]"
[2156][giles@nikola:~]$
[2156][giles@nikola:~]$ d
bin mail
[2157][giles@nikola:~]$ unset PROMPT_COMMAND
[giles@nikola:~]
echo -n ...
beheert de uitvoer van het date
commando en
onderdrukt de opvolgende newline, waardoor de prompt geheel op één
regel kan verschijnen. Aan het einde maakte ik gebruik van het unset
commando om de omgevingsvariabele PROMPT_COMMAND te verwijderen.
Je kunt tevens direct de uitvoer van reguliere Linux-commando's in de prompt gebruiken. Uiteraard wil je niet al te veel materiaal invoegen, anders zal het een grote prompt creëren. Je zult een snel commando willen omdat het iedere keer dat je prompt op het scherm verschijnt zal worden uitgevoerd.Onderbrekingen in de weergave van je prompt terwijl je aan het werken bent kan zeer ergerlijk zijn. (In tegenstelling tot het vorige voorbeeld waar dit veel op lijkt, werkt dit wel met Bash 1.14.7).
[21:58:33][giles@nikola:~]$ PS1="[\$(date +%H%M)][\u@\h:\w]\$ "
[2159][giles@nikola:~]$ ls
bin mail
[2200][giles@nikola:~]$
Let goed op de backslash voor het dollar-teken van de commando substitutie. Zonder die backslash wordt het externe commando exact éénmaal uitgevoerd, als de PS1-string in de omgeving wordt gelezen. Voor deze prompt zou dat betekenen dat het ongeacht hoelang de prompt in gebruik was, dezelfde tijd zou tonen. De backslash schermt de inhoud van $() af van onmiddellijke shell-interpretatie , dus "date" wordt iedere keer dat een prompt wordt gegenereerd, aangeroepen.
Linux wordt met veel kleine utility's geleverd, zoals date, grep, of wc waarmee je data kunt manipuleren. Als je merkt dat je probeert complexe combinaties van deze programma's binnenin een prompt aan te maken, kan het eenvoudiger zijn om er een eigen alias, functie of shell-script van te maken en het vanuit de prompt aan te roepen. Escape sequences zijn vaak vereist in bash shell-scripts om er zeker van te zijn dat shell-variabelen op de juiste tijd worden uitgewerkt (zoals te zien in het date-commando hierboven): dit komt op een ander niveau binnen de prompt PS1-regel naar boven, en het voorkomen ervan door het aanmaken van functies is een goed idee.
Een voorbeeld van een klein shell-script dat binnen een prompt wordt gebruikt, wordt hieronder gegeven:
#!/bin/bash # lsbytesum - geef het totaal aantal bytes in een directorylisting TotalBytes=0 for Bytes in $(ls -l | grep "^-" | cut -c30-41) do let TotalBytes=$TotalBytes+$Bytes done TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc) echo -n "$TotalMeg"
Ik heb dit tijden zowel als een functie als in een shell-script in mijn ~/bin directory bewaard, die zich in mijn path bevindt. Gebruikt in een prompt:
[2158][giles@nikola:~]$ PS1="[\u@\h:\w (\$(lsbytesum) Mb)]\$ "
[giles@nikola:~ (0 Mb)]$ cd /bin
[giles@nikola:/bin (4.498 Mb)]$
Je zult zien dat ik mijn gebruikersnaam, computernaam, de tijd en huidige directorynaam in mijn meeste prompts gebruik. Met uitzondering van de tijd, zijn dit zeer standaard-items die in een prompt te vinden zijn, en tijd is waarschijnlijk de eerstvolgende algemene aanvulling. Maar wat je opneemt is geheel een kwestie van smaak. Hier zijn wat voorbeelden van mensen die ik ken om je op ideeën te brengen.
Dan's prompt is minimaal, maar zeer effectief, vooral voor de manier waarop hij werkt.
[giles@nikola:~]$ cur_tty=$(tty | sed -e "s/.*tty\(.*\)/\1/")
[giles@nikola:~]$ echo $cur_tty
p4
[giles@nikola:~]$ PS1="\!,$cur_tty,\$?\$ "
1095,p4,0$
Dan houdt er niet van als de huidige werkdirectory de prompt drastisch van grootte doet veranderen, als je je door de directorystructuur verplaatst, dus onthoudt hij dit (of typt "pwd"). Hij leerde Unix met csh en tcsh, dus maakt hij veelvuldig gebruik van de commando-historie (iets dat velen van ons betreurden dat Bash dit niet deed). Dus het eerste item in de prompt is het historie-nummer. Het tweede item bestaat uit de veelbetekenende tekens van de tty (de uitvoer van "tty" is er met sed uitgeknipt), een item dat handig kan zijn voor "screen" gebruikers. Het derde item is de exit waarde van het laatste commando/pipeline (merk op dat deze weergave nutteloos is door enig commando uitgevoerd binnen de prompt. Je zou dit echter op kunnen lossen door het in een variabele af te vangen en het terug te spelen). Als laatste is het "\$" een dollar-teken voor een reguliere gebruiker en verandert in een hekje ("#") als de gebruiker root is.
Torben Fjerdingstad (tfj@fjerdingstad.dk) schreef me om me te vertellen dat hij zijn jobs vaak uitstelt en ze dan vaak vergeet. Hij gebruikt zijn prompt om zichzelf aan uitgestelde taken (suspended jobs) te herinneren:
[giles@nikola:~]$ function jobcount {
> jobs|wc -l| awk '{print $1}'
> }
[giles@nikola:~]$ export PS1='\W[`jobcount`]# '
giles[0]# man ls &
[1] 4150
[1]+ Stopped (tty output) man ls
giles[1]#
Torben gebruikt awk om de blanco's uit de uitvoer van wc te halen, terwijl ik gebruik zou hebben gemaakt van sed of tr, niet omdat die beter zijn, maar omdat ik daar meer bekend mee ben. Er zijn waarschijnlijk ook nog andere manieren. Torben plaatst ook nog enkele aanhalingstekens om zijn PS1-string, wat voorkomt dat Bash de aanhalingstekens openen (`) onmiddellijk interpreteert. Dus hoeft hij ze niet, zoals ik noemde, te escapen.
NOOT: Er is een bekende bug in Bash 2.02 die er voor zorgt dat een jobs commando (een intern shell-commando) naar een pipe niets retourneert. Als je het bovenstaande onder Bash 2.02 probeert, zul je altijd een "0" terug krijgen, ongeacht hoeveel jobs je hebt uitgesteld. Dit probleem is in 2.03 hersteld.