Category Archives: Bash

Ik werk al jaren met de Bash, de Bourne Again Shell. En ik gebruik hem tot mijn spijt nog altijd als een soort veredelde Korn Shell en daarmee doe ik mezelf tekort. Dus schrijf ik zo af en toe een stukje voor mezelf, als ik weer een mooie feature ontdekt heb. Als iemand anders er ook wat aan heeft, zoveel te beter.

Geef een Gnome terminal window een naam

Door Jan Sepp, maaart 2022

Ooit, in de Common Desktop Environment (CDE), kon je ieder terminal window eenvoudig een eigen naam geven met een rechter muisklik in de header. Helaas werkt dat niet voor Gnome-terminal. Toch heb ik dat nodig: ik heb regelmatig naast elkaar een command-line window open, en een of twee of zelfs drie windows waar MySQL in draait en dan vaak ook nog een window met een editor. Allemaal hebben ze dezelfde naam: Terminal. Ik klik dus altijd verkeerd. Het is een kleine ergernis, maar hoe prettig zou het niet zijn als elk van die terminals gewoon een duidelijke naam had, die aangeeft wat ik in die terminal heb draaien. Een terminal een naam geven kàn gelukkig wel, maar het is wel veel ingewikkelder dan die eenvoudige muisklik uit de CDE.

Dit artikeltje slaat alleen op het programma gnome-terminal, en al mijn voorbeelden geef ik in de bash (bourne-again shell). Nog een stapje terug: ik heb het over Linux. Als je iets anders gebruikt heb je dus niet zoveel aan dit artikel. Maar de combinatie bash met gnome-terminal komt heel veel voor in Linux. En voor de echte beginnelingen: de dollar vooraan ieder commando dat ik geef moet je niet inkloppen, dat is de “prompt” die aangeeft dat Linux klaar staat om een volgend commando te ontvangen.

De eerste terminal

Zijn er nog die-hards die alleen maar op de command line werken? Ja hoor, als je een aantal grote servers te beheren hebt kan een grafische schil (zeg maar: een windows systeem) behoorlijk veel overhead kosten: CPU-tijd en geheugenruimte die je wel voor wat beters kunt gebruiken. Maar ik gebruik mijn machine als een PC, en ik ben erg blij met mijn grafische omgeving. Toch heb ik regelmatig een terminal nodig1Gnome terminal is eigenlijk geen terminal, maar een terminal emulatie programma., bijvoorbeeld voor het beheer van de databases die ik onderhoud voor de Stichting ScheepsHistorisch Onderzoek (s2ho) en voor het aanroepen van de text-editor die ik het beste ken: vi.

De allereerste terminal roep ik aan vanuit mijn grafische omgeving. Ik kan dat doen via het menu, maar ik open zò vaak een terminal window dat ik het icoontje op mijn taakbalk heb staan. De eerste terminal roep ik aan met dit icoontje:

Afb: terminal icoon
Open een terminal vanaf de taakbalk

Het probleem

Nou ja, probleem. Ik erger me eraan dat alle terminal windows die ik open een vaste naam hebben: Terminal. Dit is wat ik bedoel:

Afb. Standaard gnome-terminal
Screenshot 1: Drie terminals in drie tabs. Alle drie heten ze Terminal

Als ik zes van die tabs open heb, heten ze alle zes Terminal. Dat moet toch anders kunnen?

Een openstaande terminal van naam veranderen

Ja, dat kan anders. Met een escape code kan ik de terminal een andere naam geven. Als ik in de huidige tab het commando geef:

$ printf “\033]0;Terminalnaam\007”

dan is het resultaat dat de tab van waaruit ik dat commando geef tot nader order Terminalnaam heet:

Afb: stel interactief een nieuwe naam in voor een bestaande terminal
Screenshot 2: Stel interactief een nieuwe naam in voor een bestaande terminat(-tab)

Er zijn wel wat beperkingen: je moet dit commando per sé vanaf de command-line geven in de terminal die je wilt veranderen. Met andere woorden: je kunt niet vanuit de ene terminal de naam van een andere terminal aanpassen, en als er al een programma in een terminal draait (bijvoorbeeld een MySQL of VI sessie) dan kun je niet vanuit dat programma de naam veranderen. Maar … goed genoeg voor mijn doeleinden.

Dus even deze merkwaardige escape code uit je hoofd leren? Nou, liever niet. Dit is typisch iets wat je in één van de initialisatiebestanden zet. In dit geval in de $HOME/.bashrc, het bestand dat door ieder proces dat je start gelezen wordt. Met mijn favoriete editor voeg ik het commando als een functie toe aan de .bashrc:

function termtitle() { printf “\033]0;$*\007”; }

Niet vergeten op te slaan. Daarna kan ik het in iedere willekeurige terminal aanroepen:

$ termtitle Hallo Wereld!

Een paar opmerkingen hierbij:

  • De naam van de functie doet er niet toe. Ik noem hem termtitle, maar je mag iedere willekeurige (unieke) naam gebruiken. Maar dan moet je hem natuurlijk ook wel met die naam aanroepen.
  • In de functie-definitie gebruik ik “$*” als plaatshouder voor de terminalnaam. $* betekent: alle parameters die bij de aanroep volgen op de programmanaam. Je mag hem dus aanroepen als termtitle Hallo Wereld! (2 parameters) of als termtitle “Hallo Wereld!” (1 parameter).

Het resultaat is:

Afb. Geef een bestaande tab een nieuwe naam
Screenshot 3: Aanroepen van de door mijzelf gedefinieerde functie termtitle

Een terminal een naam geven bij de aanroep

Als je een nieuwe terminal meteen bij de aanroep al een naam mee wilt geven dan doe je dat met het commando:

$ gnome-terminal -t Terminal-3

Terminal-3 wordt dan geopend in een nieuw terminalvenster. Je mag ook, in plaats van -t, opgeven –title Terminalnaam. Het is meer tikwerk, maar wel duidelijker. Temeer daar er ook een –tab bestaat (die je niet mag afkorten), waarmee je forceert dat de terminal die je opent in een tab verschijnt, en dus niet in een eigen venster. Ziehier het resultaat:

Afb. 4: Open een terminal in een tab
Screenshot 4: Open een terminal met een eigen titel in een tab in een nieuw of in een bestaand terminal window.

Weer een stap verder: je kunt een terminal openen en daar meteen een programma in starten. Dat doe je door achter de laatste van de terminalparameters de code ” — ” te plaatsen (2 keer een minteken, omgeven door spaties) om aan te duiden dat je klaar bent met de terminal parameters. Daar weer achter zet je dan de aanroep van je eigenlijke programma:

Afb. Open een programma in een terminal met een eigen naam
Screenshot 5: Open een programma (in dit geval de MariaDB client) in een terminal met een eigen naam

Dat is (zie het buiterste scherm) weer een mondvol om te typen. Als je regelmatig hetzelfde programma, met dezelfde parameters , in een terminal moet starten kun je overwegen om ook dat in je .bashrc op te nemen. Dat hoeft niet eens in een functie, je kunt er een “alias” van maken. Een alias is niets meer (of minder) dan een enkel woord dat een … eeh … alias is voor een heel commando. Dus bovenstaand commando wordt als alias in de .bashrc:

alias MDB=”gnome-terminal –title MariaDB-2 -u jan -p”

Let op: geen spaties rond het “=”-teken en het hele commando tussen aanhalingstekens. Als ik dat eenmaal gedefinieerd heb roep ik dat hele commando eenvoudig aan met – in dit geval – het alias MDB:

Afb: Aanroepen van een alias
Screenshot 6: het aanroepen van een alias dat is voorgedefinieerd in de .bashrc

Nog één klein puntje: je hoeft noch de functies, noch de aliassen in de .bashrc te exporteren. Ze zijn automatisch beschikbaar voor ieder programma dat je aanroept – natuurlijk wel pas als je eerst de aangepaste .bashrc ge-savet hebt.

Besluit

Het is niet mogelijk om een gnome-terminal een naam te geven met een rechter muisklik. Je kunt wel een bestaande terminal (of terminal-tab) een nieuwe naam geven met een nogal onhandige escape-code, die ik in ieder geval niet wens te onthouden. Dus is het handiger om die code in een functie in je .bashrc te zetten.

Je kunt ook een nieuwe terminal (in een tab of in een eigen window) aanroepen met een zelfgekozen naam. Desgewenst kun je zelfs meteen een programma in zo’n terminal window starten.

Ten slotte kun je ook dat weer nog een stapje verder automatiseren door dat commando als een alias te definiëren.

Batch rename in Bash

De Bash kent een commando “rename”. Dat is een Perl script, oorspronkelijk geschreven door Larry Wall zelf.

Omdat het Perl is, kun je er Regular Expressions in gebruiken. En dus kun je batch renames doen.

Het formaat is heel algemeen: $ rename ‘RE’ file(s)

Je mag een -n (no execute) optie gebruiken om te zien of hij doet wat je denkt dat hij gaat doen.

Augustus 2014 moest ik een zootje bestanden op volgorde converteren van .CSV naar .SQL. Die conversie doet er voor dit stukje niet toe, de volgorde wel. Natuurlijk kreeg ik ze aangeleverd als:

$ ls -l
total 10184
-rw-r--r-- 1 george users 265787 aug 24 14:02 ligger-R10-V8.csv
-rw-r--r-- 1 george users  76069 aug 24 14:02 ligger-R11-V8.csv
-rw-r--r-- 1 george users 124062 aug 24 14:02 ligger-R12-V8.csv
-rw-r--r-- 1 george users 490224 aug 24 14:03 ligger-R13-V8.csv
-rw-r--r-- 1 george users 495891 aug 24 14:03 ligger-R14-V8.csv
-rw-r--r-- 1 george users 505636 aug 24 14:04 ligger-R15-V8.csv
-rw-r--r-- 1 george users 355910 aug 24 14:04 ligger-R16-V8.csv
-rw-r--r-- 1 george users 285517 aug 24 14:04 ligger-R17-V8.csv
-rw-r--r-- 1 george users 286558 aug 24 14:05 ligger-R18-V8.csv
-rw-r--r-- 1 george users 309178 aug 24 14:05 ligger-R19-V8.csv
-rw-r--r-- 1 george users 306770 aug 24 13:59 ligger-R1-V8.csv
-rw-r--r-- 1 george users 303128 aug 24 14:05 ligger-R20-V8.csv
-rw-r--r-- 1 george users 315000 aug 24 14:05 ligger-R21-V8.csv
-rw-r--r-- 1 george users 350637 aug 24 14:06 ligger-R22-V8.csv
-rw-r--r-- 1 george users 318737 aug 24 14:06 ligger-R23-V8.csv
-rw-r--r-- 1 george users 324801 aug 24 14:07 ligger-R24-V8.csv
-rw-r--r-- 1 george users 305521 aug 24 14:07 ligger-R25-V8.csv
-rw-r--r-- 1 george users 314024 aug 24 14:07 ligger-R26-V8.csv
-rw-r--r-- 1 george users 302716 aug 24 14:08 ligger-R27-V8.csv
-rw-r--r-- 1 george users 295766 aug 24 14:08 ligger-R28-V8.csv
-rw-r--r-- 1 george users 315698 aug 24 14:08 ligger-R29-V8.csv
-rw-r--r-- 1 george users 274858 aug 24 13:59 ligger-R2-V8.csv
-rw-r--r-- 1 george users 249957 aug 24 14:08 ligger-R30-V8.csv
-rw-r--r-- 1 george users 286666 aug 24 14:00 ligger-R3-V8.csv
-rw-r--r-- 1 george users 254408 aug 24 14:00 ligger-R4-V8.csv
-rw-r--r-- 1 george users 242216 aug 24 14:00 ligger-R5-V8.csv
-rw-r--r-- 1 george users 242523 aug 24 14:01 ligger-R6-V8.csv
-rw-r--r-- 1 george users 280042 aug 24 14:01 ligger-R7-V8.csv
-rw-r--r-- 1 george users 285156 aug 24 14:01 ligger-R8-V8.csv
-rw-r--r-- 1 george users 237586 aug 24 14:02 ligger-R9-V8.csv
-rw-r--r-- 1 george users  64329 aug 24 14:09 ligger-RN1-V8.csv
-rw-r--r-- 1 george users 302521 aug 24 14:09 ligger-RN2-V8.csv
-rw-r--r-- 1 george users 288242 aug 24 14:10 ligger-RN3-V8.csv
-rw-r--r-- 1 george users 280021 aug 24 14:10 ligger-RN4-V8.csv
-rw-r--r-- 1 george users 276758 aug 24 14:10 ligger-RN5-V8.csv
$

Met andere woorden: R1 komt na R19, R2 komt na R20 en R3 tot en met R9 komen na R30. Ik had ze natuurlijk gemakkelijk zat stuk voor stuk kunnen hernoemen , maar iets dergelijks gebeurt regelmatig, dus kan het niet structureler? Ik vind dat je mensen die niet in de IT werken niet mag lastig vallen met ASCII (of tegenwoordig Unicode) sorteervolgordes. Voor gewone mensen komt negen voor tien. Kortom, ik besloot ‘even’ een RE te schrijven:

$ rename -n 's/(.*)R([123456789])-(.*)/$1R0$2-$3/' *.csv
ligger-R1-V8.csv renamed as ligger-R01-V8.csv
ligger-R2-V8.csv renamed as ligger-R02-V8.csv
ligger-R3-V8.csv renamed as ligger-R03-V8.csv
ligger-R4-V8.csv renamed as ligger-R04-V8.csv
ligger-R5-V8.csv renamed as ligger-R05-V8.csv
ligger-R6-V8.csv renamed as ligger-R06-V8.csv
ligger-R7-V8.csv renamed as ligger-R07-V8.csv
ligger-R8-V8.csv renamed as ligger-R08-V8.csv
ligger-R9-V8.csv renamed as ligger-R09-V8.csv
$

Die RE s/(.*)R([123456789])-(.*)/$1R0$2-$3/ behoeft misschien enige uitleg:

  • De eerste “s” is substitute (zoek en vervang)
  • Drie slashes: /zoekpatroon/vervangpatroon/
  • De (toevallig ook drie paar) ronde haken in het zoekpatroon kopiëren deel-patronen. Die zet ik in het vervangpatroon weer op hun plaats met $1, $2 en $3
  • In de eerste set ronde haken staat het patroon (.*): een willekeurig teken, nul of meer keer herhaald.
  • Dat eerste patroon wordt aan de achterkant begrensd door de eerste de beste “R”. Dus het zoekpatroon kopieert “ligger-“. Dat wordt met $1 in het vervangpatroon letterlijk zo teruggezet.
  • Dan volgt de letter R als begrenzing. Die zet ik in het vervangpatroon ook letterlijk weer terug.
  • Dan volgt een zoekpatroon [123456789]. Dat wil zeggen dat ik zoek naar precies één teken: een 1 of een 2, of een 3 … of een 9. Ik kopieer dat ene teken met de tweede set ronde haken  ([123456789]). Dat zet ik in het vervangpatroon terug als $2, maar wel met een 0 ervoor. Bij nader inzien had het zoekpatroon nog korter gekund: [0-9] had ook gewerkt.
  • Het tweede zoekpatroon wordt begrensd door het letterlijke teken “-“. Dat komt in het vervangpatroon ook letterlijk weer terug.
  • De derde set ronde haken  (.*) kopieert alles achter het min teken – in feite weer een willekeurig teken, nul of meer keer herhaald. Dat zet ik in het vervangpatroon terug als $3.

En daarna natuurlijk uitgevoerd zonder de -n.  Hier is de proof of the pudding:
$ rename  's/(.*)R([123456789])-(.*)/$1R0$2-$3/' *.csv
$ ls -l
total 10184
-rw-r--r-- 1 george users 306770 aug 24 13:59 ligger-R01-V8.csv
-rw-r--r-- 1 george users 274858 aug 24 13:59 ligger-R02-V8.csv
-rw-r--r-- 1 george users 286666 aug 24 14:00 ligger-R03-V8.csv
-rw-r--r-- 1 george users 254408 aug 24 14:00 ligger-R04-V8.csv
-rw-r--r-- 1 george users 242216 aug 24 14:00 ligger-R05-V8.csv
-rw-r--r-- 1 george users 242523 aug 24 14:01 ligger-R06-V8.csv
-rw-r--r-- 1 george users 280042 aug 24 14:01 ligger-R07-V8.csv
-rw-r--r-- 1 george users 285156 aug 24 14:01 ligger-R08-V8.csv
-rw-r--r-- 1 george users 237586 aug 24 14:02 ligger-R09-V8.csv
-rw-r--r-- 1 george users 265787 aug 24 14:02 ligger-R10-V8.csv
-rw-r--r-- 1 george users  76069 aug 24 14:02 ligger-R11-V8.csv
-rw-r--r-- 1 george users 124062 aug 24 14:02 ligger-R12-V8.csv
-rw-r--r-- 1 george users 490224 aug 24 14:03 ligger-R13-V8.csv
-rw-r--r-- 1 george users 495891 aug 24 14:03 ligger-R14-V8.csv
-rw-r--r-- 1 george users 505636 aug 24 14:04 ligger-R15-V8.csv
-rw-r--r-- 1 george users 355910 aug 24 14:04 ligger-R16-V8.csv
-rw-r--r-- 1 george users 285517 aug 24 14:04 ligger-R17-V8.csv
-rw-r--r-- 1 george users 286558 aug 24 14:05 ligger-R18-V8.csv
-rw-r--r-- 1 george users 309178 aug 24 14:05 ligger-R19-V8.csv
-rw-r--r-- 1 george users 303128 aug 24 14:05 ligger-R20-V8.csv
-rw-r--r-- 1 george users 315000 aug 24 14:05 ligger-R21-V8.csv
-rw-r--r-- 1 george users 350637 aug 24 14:06 ligger-R22-V8.csv
-rw-r--r-- 1 george users 318737 aug 24 14:06 ligger-R23-V8.csv
-rw-r--r-- 1 george users 324801 aug 24 14:07 ligger-R24-V8.csv
-rw-r--r-- 1 george users 305521 aug 24 14:07 ligger-R25-V8.csv
-rw-r--r-- 1 george users 314024 aug 24 14:07 ligger-R26-V8.csv
-rw-r--r-- 1 george users 302716 aug 24 14:08 ligger-R27-V8.csv
-rw-r--r-- 1 george users 295766 aug 24 14:08 ligger-R28-V8.csv
-rw-r--r-- 1 george users 315698 aug 24 14:08 ligger-R29-V8.csv
-rw-r--r-- 1 george users 249957 aug 24 14:08 ligger-R30-V8.csv
-rw-r--r-- 1 george users  64329 aug 24 14:09 ligger-RN1-V8.csv
-rw-r--r-- 1 george users 302521 aug 24 14:09 ligger-RN2-V8.csv
-rw-r--r-- 1 george users 288242 aug 24 14:10 ligger-RN3-V8.csv
-rw-r--r-- 1 george users 280021 aug 24 14:10 ligger-RN4-V8.csv
-rw-r--r-- 1 george users 276758 aug 24 14:10 ligger-RN5-V8.csv
$

Tevreden!

Er is zelfs een man page voor rename. Het wordt nog eens wat met Linux!