리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $1, $# 받기

TestomgevingRHEL-familieAlmaLinux 9.8bash 5.1root-account
Shell$1$#--

Linux-opdrachtregelargumenten (command-line argument) zijn waarden die je aan een programma meegeeft door ze, gescheiden door spaties, achter de opdrachtnaam te schrijven. We gaven op een AlmaLinux 9-server opties, aanhalingstekens, jokertekens en -- mee aan een testscript dat de ontvangen argumenten ongewijzigd toont: het opsplitsen van de argumenten deed de shell, en het lezen van de opties deed elke opdracht zelf.

De uitvoer hieronder is precies wat we kregen met bash 5.1 onder het root-account van een AlmaLinux 9.8-server. De testscripts en voorbeeldbestanden zijn in een aparte werkmap gemaakt, en het pad /home/user/www is een voorbeeldwaarde.

1️⃣ Wat zijn Linux-opdrachtregelargumenten?

Typ je op de opdrachtregel iets als [opdracht arg1 arg2], dan splitst de shell de woorden op bij de spaties. Het eerste woord wordt het programma dat wordt uitgevoerd, en de overige woorden gaan op volgorde als argumenten naar dat programma.

Om de meegegeven argumenten te zien, maakten we args.sh in de werkmap. $0 bevat de naam waarmee het werd gestart, $# het aantal argumenten, en vanaf $1 staan de argumenten op volgorde. De vierkante haken laten zien waar elk argument begint en eindigt.

#!/bin/bash
echo "\$0 = $0"
echo "\$# = $#"
i=1
for a in "$@"; do
  echo "\$$i = [$a]"
  i=$((i+1))
done

We gaven het script uitvoerrechten en startten het met drie woorden: a, b en c.

./args.sh a b c
$0 = ./args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

De drie woorden kwamen in $1, $2 en $3 terecht, en $# was 3. Start je het script door de naam achter bash te schrijven, dan bevat $0 precies de geschreven naam, args.sh.

bash args.sh a b c
$0 = args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

Alleen $0 veranderde in args.sh; de drie argumenten en het aantal bleven hetzelfde als eerst.

2️⃣ Opdrachtregelargumenten en opdrachtopties

Linux-opdrachten schrijf je meestal in de volgorde [opdracht -optie argument]. Opties veranderen hoe de opdracht werkt, en argumenten bepalen met welke bestanden, paden of waarden de opdracht werkt.

ls -l /home/user/www

Voor de shell is ook -l gewoon een argument. Toen we dezelfde woorden aan args.sh meegaven, kwam -l in $1 en het pad in $2.

./args.sh -l /home/user/www
$0 = ./args.sh
$# = 2
$1 = [-l]
$2 = [/home/user/www]

-l lezen als optie is het werk van ls. Daarom betekent dezelfde letter per opdracht iets anders: -n bij head bepaalt het aantal regels dat wordt getoond, terwijl -n bij ls eigenaren als nummer toont in plaats van als naam.

Sommige opties nemen het woord direct erna als eigen waarde. In de opdracht find neemt -type de f en -name de "*.txt" als waarde; zo'n waarde die bij een optie hoort, heet een optieargument.

find . -type f -name "*.txt"

De . vooraan in deze opdracht is een argument dat bij geen enkele optie hoort en bepaalt de map waar het zoeken begint.

3️⃣ Notaties van Linux-opdrachtopties

Korte opties beginnen met één streepje, bestaan uit één letter en kun je aan elkaar schrijven. Eerst toonden we de map site in de werkmap met [ls -l -a].

ls -l -a site
total 8
drwxr-xr-x 3 root root  52 Oct 28 16:00 .
drwxr-xr-x 3 root root 137 Oct 29 01:20 ..
-rw-r--r-- 1 root root  17 Oct 28 16:00 .htaccess
drwxr-xr-x 2 root root  23 Oct 28 16:00 css
-rw-r--r-- 1 root root  14 Oct 28 16:00 index.html

Daarna vergeleken we dat met diff met de uitvoer van [ls -la], waarin de twee letters aan elkaar staan.

diff <(ls -l -a site) <(ls -la site) && echo same
same

De twee uitvoeren verschilden geen enkel teken. Lange opties beginnen met twee streepjes en schrijf je als woord; --all van ls is dezelfde optie als -a, dus [ls -l --all site] gaf ook hetzelfde resultaat.

Lange opties worden ook geaccepteerd als je alleen het begin schrijft, zolang dat maar bij één optie past. --al paste bij twee opties, --all en --almost-all, dus ls toonde geen lijst en stopte met afsluitcode 2.

ls --al site
ls: option '--al' is ambiguous; possibilities: '--all' '--almost-all'
Try 'ls --help' for more information.

Opties met een waarde kun je op verschillende manieren schrijven. Toon je met head de eerste twee regels van a.txt, dan kan de korte optie de waarde direct vastgeplakt krijgen: [-n2].

head -n2 a.txt
alpha
beta

Bij de lange optie koppel je de waarde met een isgelijkteken: [--lines=2].

head --lines=2 a.txt
alpha
beta

Alle vier de vormen, ook [-n 2] en [--lines 2] met een spatie, toonden de twee regels alpha en beta.

ls, head en cat lezen hun opties met de functie getopt_long van de C-bibliotheek. Toen we de drie programmabestanden met strings bekeken, bevatten ze allemaal deze functienaam.

Om dezelfde regels vanuit de shell te controleren, gebruik je de opdracht getopt uit util-linux. Achter -o schrijf je de korte opties en achter -l de lange; een dubbele punt achter een letter betekent dat de optie een waarde verwacht.

getopt -o lan: -l all,lines: -- -la -n 2 --all a.txt
 -l -a -n '2' --all -- 'a.txt'

De aan elkaar geschreven -la werd gesplitst in -l en -a, en -n 2 werd samengevoegd tot -n met de waarde 2. a.txt, dat geen optie is, werd naar het einde verplaatst, achter --.

4️⃣ Argumenten tussen aanhalingstekens en jokertekens

Een bestandsnaam met een spatie moet tussen aanhalingstekens staan om als één argument mee te gaan.

./args.sh "my file.txt" report.txt
$0 = ./args.sh
$# = 2
$1 = [my file.txt]
$2 = [report.txt]

Zonder aanhalingstekens werden my en file.txt apart opgesplitst en werd $# 3. Geef je het zo mee aan ls of cat, dan zoeken die naar twee bestanden met de namen my en file.txt.

./args.sh my file.txt report.txt
$0 = ./args.sh
$# = 3
$1 = [my]
$2 = [file.txt]
$3 = [report.txt]

Jokertekens vervangt de shell door bestandsnamen voordat het programma ze ontvangt. Toen we in de werkmap *.txt meegaven, kwamen de vier bestanden die op .txt eindigen binnen, op naam gesorteerd.

./args.sh *.txt
$0 = ./args.sh
$# = 4
$1 = [a.txt]
$2 = [b.txt]
$3 = [my file.txt]
$4 = [report.txt]

De "*.txt" tussen aanhalingstekens werd niet door de shell vervangen en werd letterlijk één argument. Bij opties zoals -name van find, waar het programma het patroon zelf vergelijkt, geef je het zo tussen aanhalingstekens mee.

./args.sh "*.txt"
$0 = ./args.sh
$# = 1
$1 = [*.txt]

Ook lege aanhalingstekens gaan mee als één leeg argument. Bij [./args.sh '' b] was $# 2 en was $1 leeg.

5️⃣ Einde van de opdrachtopties (--)

Een argument dat met een streepje begint, zoals een bestand met de naam -n, leest de opdracht als optie. Toen we [ls -n] uitvoerden in de map dash, die alleen dat ene bestand bevat, nam ls -n niet als bestandsnaam maar als optie voor numerieke uitvoer en toonde het de inhoud van de map.

ls -n
total 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -n

Argumenten achter -- worden niet als opties gelezen, ook als ze met een streepje beginnen. [ls -- -n] toonde alleen de bestandsnaam -n.

ls -- -n
-n

Binnen één opdracht worden dezelfde tekens voor en na -- verschillend gelezen. Toen we -n twee keer aan cat meegaven, werd de eerste -n gelezen als optie voor regelnummers en de -n na -- als bestandsnaam, zodat de inhoud van het bestand met regelnummers verscheen.

cat -n -- -n
     1	dash file

Je kunt er ook een pad voor zetten en ./-n schrijven; dan begint het argument niet met een streepje en wordt het als hetzelfde bestand -n gelezen.

Dat -- als einde van de opties wordt gelezen, is ook een regel aan de kant van de opdracht. Toen we het meegaven aan args.sh, dat geen opties leest, kwam ook -- ongewijzigd in $1 terecht.

./args.sh -- -a
$0 = ./args.sh
$# = 2
$1 = [--]
$2 = [-a]

De POSIX Utility Conventions bepalen dat de eerste -- die geen optieargument is, wordt aanvaard als het einde van de opties. Daarom schrijf je bij opdrachten die deze conventies volgen bestandsnamen die met - beginnen achter --.

6️⃣ Opdrachtregelargumenten ontvangen in een shellscript

Een shellscript leest de ontvangen argumenten via positionele parameters en speciale parameters. Ook main(int argc, char *argv[]) van een C-programma krijgt dezelfde argumenten; naast elkaar gezet ziet dat er zo uit.

ParameterWaarde die erin staatC-functie main
$0Naam van het uitgevoerde scriptargv[0]
$1 ~ $9Eerste tot en met negende argumentargv[1] ~ argv[9]
${10}Vanaf het tiende argument tussen accoladesargv[10]
$#Aantal argumenten, $0 niet meegeteldargc - 1
"$@"Alle argumenten, elk apartargv[1] tot het einde
"$*"Alle argumenten met spaties samengevoegd tot één—

Een Python-programma krijgt dezelfde argumenten als de lijst sys.argv. Toen we met [python3 -c] drie argumenten meegaven, kwam de tussen aanhalingstekens gezette my file.txt in één element van de lijst terecht, en in het eerste element stond -c.

python3 -c 'import sys; print(sys.argv)' a "my file.txt" -l
['-c', 'a', 'my file.txt', '-l']

"$@" en "$*" geven tussen dubbele aanhalingstekens een verschillend resultaat. Om het verschil te zien, maakten we star.sh, dat beide vormen na elkaar toont.

#!/bin/bash
echo 'with "$@"'
printf '  [%s]\n' "$@"
echo 'with "$*"'
printf '  [%s]\n' "$*"

We startten star.sh met drie argumenten: a, "b c" en d.

./star.sh a "b c" d
with "$@"
  [a]
  [b c]
  [d]
with "$*"
  [a b c d]

"$@" gaf de drie argumenten apart door, terwijl "$*" ze met spaties samenvoegde en als één doorgaf.

Geef je de ontvangen argumenten ongewijzigd door aan een andere opdracht, gebruik dan dus "$@".

shift gooit $1 weg en schuift de overige argumenten één plaats naar voren. Je gebruikt het in scripts die eerst één optie lezen en de rest als lijst met bestanden behandelen.

We maakten shift.sh, dat $1 en $# voor en na shift toont.

#!/bin/bash
echo "before shift: \$1 = $1, \$# = $#"
shift
echo "after shift:  \$1 = $1, \$# = $#"

We startten shift.sh met drie argumenten: -v, a.txt en b.txt.

./shift.sh -v a.txt b.txt
before shift: $1 = -v, $# = 3
after shift:  $1 = a.txt, $# = 2

Vanaf het tiende argument zet je het getal tussen accolades, zoals ${10}. We maakten ten.sh, dat $10 en ${10} naast elkaar toont.

#!/bin/bash
echo "\$10 = $10"
echo "\${10} = ${10}"

We gaven ten.sh 11 argumenten mee, a tot en met k.

./ten.sh a b c d e f g h i j k
$10 = a0
${10} = j

$10 werd a0, dus $1 met een 0 erachter, terwijl ${10} het tiende argument j werd.

🔲 Simulator voor opdrachtregelargumenten

In de simulator hieronder kun je aanhalingstekens, jokertekens en -- aan args.sh meegeven en ook zelf opdrachten typen om te zien hoe ls en getopt opties lezen en hoe star.sh en shift.sh argumenten ontvangen.

Simulator voor opdrachtregelargumentenbash 5.1
[root@server work]#
Een virtuele AlmaLinux-server die alleen in je browser draait; args.sh toont de ontvangen argumenten met hun nummer, en met ↑↓ haal je eerder gebruikte opdrachten terug.

🔢 FAQ & aanbevolen content

De bovengrens voor de totale lengte van argumenten en omgevingsvariabelen controleer je met [getconf ARG_MAX]; op de AlmaLinux 9.8-server was dat 2097152 bytes. Boven die grens start het programma niet en krijg je de fout [Argument list too long]. Bij heel veel bestanden geef je ze niet in één keer mee met een jokerteken, maar verdeel je ze met -exec van find of met xargs.

Een argument (argument) is de waarde die je bij het uitvoeren van een opdracht echt meegeeft, en een parameter (parameter) is de naam waaronder de ontvangende kant die waarde krijgt. In een shellscript ontvangen positionele parameters zoals $1 en $2 de meegegeven argumenten.

getopts, ingebouwd in bash, leest korte opties zoals -v één voor één. Lange opties leest het niet; wil je ook lange opties zoals --verbose accepteren, orden dan eerst de argumenten met de hierboven gebruikte opdracht getopt.

ℹ️ Affiliatemelding
De content van deze site bevat affiliatelinks. Koopt een bezoeker via een van deze links een product of dienst, dan ontvangt deze site een commissie van de verkoper. Het bedrag dat de koper betaalt (bij acties gaat het omlaag ↓) wordt daardoor niet hoger. De vermelde prijzen, kortingen en voorraad gelden op het moment van schrijven en kunnen afwijken; controleer ze daarom vóór je aankoop bij de verkoper. Producten worden gekozen en beoordeeld volgens onze eigen criteria, en commissies hebben geen invloed op de volgorde of de inhoud van de beoordelingen.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Laat zien dat je geen machine bent: 7   +   7   =