De standaard bash op macOS is nog steeds bash v3:
$ bash --versionGNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)Copyright (C) 2007 Free Software Foundation, Inc.
Nog niet zo lang geleden werd bash v5 uitgebracht. De discrepantie komt van het feit dat bash gelicenseerd is als GPL v3 sinds versie 4. Apple levert geen hulpprogramma’s met een GPL v3-licentie bij macOS.
Niets weerhoudt je er echter van om de nieuwste bash-versie te downloaden en te installeren.
Nieuwe functies zijn onder andere geassocieerde arrays (d.w.z. woordenboeken) en betere auto-aanvul-setup.
Hoewel je zou denken dat dit een veel voorkomende wens is, verwijzen de meeste pagina’s die ik heb gevonden simpelweg naar Homebrew om een nieuwere bash-versie te downloaden en te installeren.
De grootste uitdaging bij het gebruik van brew is dat het niet werkt op de schaal die MacAdmins nodig hebben. brew is ontworpen voor installatie door één gebruiker, waarbij de gebruiker beheerdersrechten heeft. brew’s workflows zijn niet schaalbaar voor grote implementaties die worden gecontroleerd met een beheersysteem.
Eigenlijk zou er een package installer zijn voor de nieuwste bash versie. Helaas biedt het bash-project er geen.
In deze post zal ik laten zien hoe u de nieuwste bash-versie kunt installeren zonder brew en hoe u een installatiepakket kunt bouwen voor implementatie.
Handmatige installatie
Dit vereist dat Xcode of de Developer Command Line Tools worden geïnstalleerd.
Download eerst de broncode voor de nieuwste bash-versie van deze pagina. Op het moment van schrijven is de laatste versie bash-5.0 en het bestand dat u wilt bash-5.0.tar.gz. Eenmaal gedownload, kunt u het archief in Finder uitbreiden door te dubbelklikken.
Update: Ik heb een post met wat bijgewerkte instructies om de patches voor bash 5.0 op te nemen.
Open een Terminal venster en verander van directory naar de zojuist uitgebreide bash-5.0 directory. Start dan het configure script daar.
$ cd ~/Downloads/bash-5.0$ ./configure
Het configureer proces zal een tijdje duren, er zullen veel berichten zijn die de voortgang laten zien.
Als het configure proces eenmaal klaar is. kunt u bash bouwen met het make commando.
$ make
Dit zal de bash binary en de ondersteunende bestanden in de huidige directory bouwen. Dat is niet waar we het uiteindelijk willen hebben, maar het is waarschijnlijk een goed idee om te kijken of het bouwproces werkt. Dit zal (weer) een tijdje duren. Er zullen wat vreemd uitziende waarschuwingen zijn, maar die kunt u negeren.
Wanneer make slaagt, kunt u bash v5 daadwerkelijk installeren met
$ sudo make install
Dit bouwt en installeert de bash binary en ondersteunende bestanden in /usr/local/bin en /usr/local. sudo is nodig om /usr/local aan te passen.
Als u alleen maar op zoek was naar een manier om bash v5 te installeren zonder brew, dan bent u klaar.
Er staat echter meer nuttige informatie in de rest van de post, dus blijf lezen.
Hoe de nieuwe en de oude bash samenwerken
De standaard bash v5 binary heet bash en wordt geïnstalleerd in /usr/local/bin. De macOS standaard PATH vermeldt /usr/local/bin voor /bin waar de standaard bash v3 binary, ook bash genaamd, zich bevindt.
Dit betekent, dat wanneer een gebruiker bash in een shell typt, de versie in /usr/local/bin de voorkeur zal krijgen boven de voorgeïnstalleerde bash v3.
U kunt dit gedrag testen in Terminal. Aangezien de standaard shell nog niet is gewijzigd van /bin/bash opent de Terminal nog steeds naar bash v3. U kunt dit testen door de BASH_VERSION omgevingsvariabele te tonen:
$ echo $BASH_VERSION3.2.57(1)-release
Maar wanneer u dan bash uitvoert, zal het /usr/local/bin/bash aanroepen, dus het zal de nieuwe bash v5 uitvoeren. Het zal dit tonen in de prompt, maar u kunt ook de BASH_VERSION controleren.
$ bashbash-5.0$ echo $BASH_VERSION5.0.0(2)-release
Dit zou de setup kunnen zijn die u wilt, wanneer u bash v5 altijd wilt gebruiken. Het zou echter voor sommige gebruikers tot onverwacht gedrag kunnen leiden.
Eén optie om deze dubbelzinnigheid te vermijden is om de binary in /usr/local/bin te hernoemen naar bash5. Maar dan zullen andere hulpprogramma’s zoals env (hieronder vermeld) de binary niet meer vinden.
- Scripting OS X: Waar PATHs vandaan komen
Note: de PATH in andere contexten zal waarschijnlijk geen /usr/local/bin bevatten en de zaken verder verwarren.
bash v5 en Scripting
Scripts die bash gebruiken, moeten het volledige pad naar het binary in de shebang hebben. Op deze manier kan de script auteur bepalen of een script wordt uitgevoerd door de standaard bash v3 (/bin/bash) of de nieuwere bash v5 (/usr/local/bin/bash of /usr/local/bin/bash5).
Het wordt vaak aangeraden om het env commando in de shebang te gebruiken:
#!/usr/bin/env bash
Het env commando bepaalt het pad naar de bash binary in de huidige omgeving. (d.w.z. gebruikmakend van de huidige PATH) Dit is handig wanneer het script in verschillende omgevingen moet draaien waar de locatie van de bash binary onbekend is, met andere woorden over meerdere Unix en Unix-achtige platformen. Echter, dit maakt de werkelijke versie van bash die het script zal interpreteren onvoorspelbaar.
Bij voorbeeld, stel u heeft bash v5 geinstalleerd in de standaard configuratie (als /usr/local/bin/bash. Een script met de shebang #!/usr/bin/env bash dat wordt gestart in de gebruikersomgeving (d.w.z. vanuit Terminal) zal de nieuwere bash gebruiken, omdat /usr/local/bin voor /bin komt in de zoekvolgorde.
Wanneer u hetzelfde script in een andere context start, bijvoorbeeld als een installatiescript, een AppleScript, of een beheersysteem, zal /usr/local/bin waarschijnlijk geen deel uitmaken van de PATH in die omgeving. Dan zal de env shebang kiezen voor /bin/bash (v3). Het script zal worden geïnterpreteerd en zich mogelijk anders gedragen.
Administrators geven de voorkeur aan zekerheid in hun beheerde omgevingen. Beheerders moeten de locatie en versies van de binaries op hun systemen kennen. Voor beheerscripts moet u env vermijden en het juiste volledige pad naar de gewenste binary van de interpreter gebruiken.
De oplossingen om de dubbelzinnigheid op te lossen zijn
- gebruik het volledige pad naar de binary in de shebang
- manage en update de extra aangepaste versie van
bashmet een beheersysteem - (optioneel) hernoem de nieuwere
bashbinary naarbash5ofbash4(dit maakt het ook mogelijk ombashv4 enbashv5 beschikbaar te hebben op hetzelfde systeem) - Scripting OS X: Over de Shebang
- Scripting OS X: Het PATH in Scripts instellen
De standaard Shell van een gebruiker wijzigen in bash v5
Ondanks dat we bash v5 hebben geïnstalleerd, zal de standaard shell van een nieuw Terminal venster nog steeds de ingebouwde bash v3 gebruiken.
Het pad naar de standaard shell is opgeslagen in het gebruikersrecord. U kunt het UserShell attribuut direct wijzigen met dscl, in de ‘Geavanceerde Opties’ van het ‘Gebruikers & Groepen’ voorkeurpaneel, of in Directory Utility.
Er is ook een commando om de standaard shell in te stellen:
$ chsh -s /usr/local/bin/bashChanging shell for armin.Password for armin: chsh: /usr/local/bin/bash: non-standard shell
Het chsh (verander shell) commando zal controleren op toegestane shells in het /etc/shells bestand. U kunt eenvoudig een regel met /usr/local/bin/bash aan dit bestand toevoegen, en dan zal chsh prima werken.
$ chsh -s /usr/local/bin/bashChanging shell for armin.Password for armin:
Note: als u ervoor kiest om de bash binary te hernoemen, moet u de gewijzigde naam gebruiken in /etc/shells en met chsh.
Onthoud dat alleen het uitvoeren van chsh de shell in het huidige Terminal venster niet zal veranderen. Het is het beste om het oude Terminal venster te sluiten en een nieuw te openen om de nieuwe shell te krijgen.
Bash v5 verpakken voor massa-implementatie
Hoewel deze stappen om bash v5 op een enkele Mac te installeren en configureren eenvoudig genoeg zijn, zouden ze niet goed werken met een beheersysteem voor honderden of duizenden Macs. We willen alle bestanden die make install aanmaakt, verpakken in een package installer payload.
De --help optie van het configure script levert deze nuttige informatie op:
Tot nu toe is
make install' will install all the files in/usr/local/bin,/usr/local/libetc. You can specify an installation prefix other than/usr/localusing-prefix, for instance-prefix=$HOME`.
Wanneer we het configure script uitvoeren met de --prefix optie, maakt het een map aan die geschikt is als payload voor een package installer. We kunnen dan pkgbuild gebruiken om te bouwen om een installer pkg te maken:
$ cd ~/Downloads/bash-5.0$ mkdir payload$ ./configure --prefix=/Users/armin/Downloads/bash-5.0/payload$ make install$ pkgbuild --root payload --install-location /usr/local --identifier org.gnu.bash --version 5.0 bash-5.0.pkgpkgbuild: Inferring bundle components from contents of payloadpkgbuild: Wrote package to bash-5.0.pkg
(Opmerking: het --prefix argument vereist een absoluut pad.)
Maak het pakket
Dus, we hebben onze workflow voor het bouwen van een installatiepakket om bash v5 te distribueren en te configureren:
- download het archief
- extract het archief
- run
configuremet het--prefixargument - run
make installom de bestanden aan te maken in een payload map - optional: hernoem de resulterende
bashbinary naarbash5om conflicten te vermijden - voeg een
postinstallscript toe dat/usr/local/bin/bashtoevoegt aan/etc/shellsindien nog niet aanwezig - bouw de installer met
pkgbuild
Dit klinkt als een workflow die rijp is voor automatisering. Je kunt het script uit deze repository halen.
Je kunt een ander (geldig) bash versienummer als argument aan het script meegeven, bijv. 4.4.18. (Ik heb niets significant ouder getest.) Het script detecteert niet automatisch de laatste versie en gaat standaard uit van versie 5.0 als er geen argument wordt gegeven. Wanneer een update naar bash v5 wordt gepubliceerd, zult u de versieregel moeten aanpassen of het script met een argument moeten uitvoeren.
Ik heb (nog) niet uitgezocht hoe ik de laatste versie van de download webpagina kan detecteren. Een autopkg recept zal daarop moeten wachten. (Als iemand anders dat wil doen, graag!)