27/10/2017
At skrive Bash-scripts kan være en utrolig effektiv måde at automatisere opgaver på i et Linux-miljø. Men selv de mest erfarne udviklere kan fra tid til anden støde på kryptiske fejlmeddelelser. En af de mest almindelige, og ofte forvirrende, er unary operator expected. Denne fejl kan stoppe dit script i sit spor og efterlade dig undrende over, hvad der gik galt, især fordi ordet "unary" ikke er en del af de flestes daglige ordforråd. I denne dybdegående artikel vil vi afmystificere denne fejl, forklare præcis, hvorfor den opstår, og give dig en række robuste løsninger og bedste praksis, så du kan skrive mere fejlfrie og pålidelige scripts i fremtiden.

Hvad Betyder "Unary Operator Expected" Egentlig?
Lad os starte med at bryde selve termen ned. I programmering og matematik er en unær operator en operator, der kun arbejder på én operand (en enkelt værdi eller variabel). For eksempel er den logiske NOT-operator (!) i Bash en unær operator, fordi den inverterer værdien af det, der følger efter den. Ligeledes er filtestoperatorer som -e (tjekker om en fil eksisterer) eller -d (tjekker om det er en mappe) unære, da de kun behøver ét argument: filstien.
Når Bash returnerer fejlen "unary operator expected", fortæller den dig i bund og grund, at den forventede at finde én ting i en betinget test, men fandt noget andet – eller oftest, ingenting. Fejlen opstår typisk i forbindelse med if-sætninger og test-kommandoen, repræsenteret ved de enkelte firkantede parenteser [ ... ].
Den Grundlæggende Årsag: Tomme Variabler
Den absolut hyppigste årsag til denne fejl er en uinitialiseret eller tom variabel, der bruges i en sammenligning. Når Bash-shellen udvider (erstatter variablen med dens værdi) før den udfører testen, forsvinder variablen simpelthen, hvis den er tom. Dette efterlader test-udtrykket syntaktisk ukorrekt.
Lad os se på et klassisk eksempel:
#!/bin/bash num1="10" num2="" # Dette vil forårsage en fejl if [ $num1 -eq $num2 ]; then echo "Tallene er ens." fi
Når du kører dette script, vil du modtage en fejl, der ligner denne:
./dit_script.sh: line 7: [: 10: unary operator expected
For at forstå hvorfor, lad os se, hvad Bash ser, efter den har udvidet variablerne. Da $num2 er en tom streng, bliver linjen i praksis til:
if [ 10 -eq ]; then
Her er -eq en binær operator; den forventer en operand på hver side (den sammenligner to heltal for lighed). Men fordi $num2 var tom, er der kun én operand (10) til stede. Test-kommandoen bliver forvirret, ser operatoren -eq uden noget at sammenligne med, og konkluderer fejlagtigt, at du måske har forsøgt at bruge en unær operator, men gjorde det forkert. Deraf fejlmeddelelsen.
Effektive Løsninger til at Rette Fejlen
Heldigvis er der flere pålidelige måder at forhindre og rette denne fejl på. Valget af løsning afhænger ofte af scriptets kompleksitet og krav til kompatibilitet (portabilitet).
Løsning 1: Altid Brug Anførselstegn om Variabler
Den simpleste og mest fundamentale løsning er at omgive dine variabler med dobbelte anførselstegn (""). Dette forhindrer det, der kaldes "word splitting", og sikrer, at selvom en variabel er tom, bliver den stadig repræsenteret som en tom streng i udtrykket.
Lad os rette vores tidligere eksempel:
#!/bin/bash num1="10" num2="" # Korrekt: Brug af anførselstegn if [ "$num1" -eq "$num2" ]; then echo "Tallene er ens." fi
Efter udvidelse ser Bash nu dette:
if [ "10" -eq "" ]; then
Dette løser "unary operator expected"-fejlen. Dog introducerer det potentielt en ny, mere beskrivende fejl: integer expression expected. Dette sker fordi -eq forventer heltal, og en tom streng ("") er ikke et heltal. Selvom det er en anden fejl, er den bedre, fordi den fortæller dig præcis, hvad problemet er: du forsøger at sammenligne et tal med noget, der ikke er et tal. Dette understreger vigtigheden af at vælge den korrekte operator. Hvis du sammenligner strenge, brug = eller ==. Hvis du sammenligner heltal, skal du sikre dig, at begge variabler indeholder heltal.
Løsning 2: Brug af Dobbelte Firkantede Parenteser `[[ ... ]]`
En mere moderne og robust tilgang i Bash er at bruge de dobbelte firkantede parenteser, [[ ... ]], til betingede udtryk. Denne konstruktion er en udvidelse til Bash og er mere intelligent med hensyn til håndtering af variabler.
Inden for [[ ... ]] udføres der ikke word splitting på samme måde. Det betyder, at du kan udelade anførselstegnene omkring variabler (selvom det stadig er god praksis at bruge dem), og det vil stadig fungere korrekt, selv med tomme variabler.
#!/bin/bash num1="10" num2="" # Robust løsning med dobbelte parenteser if [[ $num1 -eq $num2 ]]; then echo "Tallene er ens." fi
Dette script vil køre uden fejl. Det vil evaluere betingelsen som falsk (da 10 ikke er lig med 0, som en tom streng ofte evalueres til i en numerisk kontekst) og fortsætte uden at printe noget. Fordelen ved [[ ... ]] er dens modstandsdygtighed over for almindelige fejl som denne. Ulempen er, at det ikke er POSIX-kompatibelt, hvilket betyder, at dit script muligvis ikke kører på ældre systemer eller med andre shells som sh.
Løsning 3: Eksplicit Test for Tomme Variabler
En tredje metode, som er en del af god defensiv programmeringspraksis, er at eksplicit tjekke, om en variabel er tom, før du forsøger at bruge den i en sammenligning. Til dette kan du bruge den unære operator -z, som returnerer sand, hvis strengen er tom.
#!/bin/bash num1="10" num2="" if [ -z "$num2" ]; then echo "Fejl: Variabel 'num2' er tom og kan ikke sammenlignes." exit 1 fi # Denne del nås kun, hvis num2 ikke er tom if [ "$num1" -eq "$num2" ]; then echo "Tallene er ens." fi
Denne tilgang gør dit script mere robust og brugervenligt, da det giver klare fejlmeddelelser i stedet for blot at fejle eller opføre sig uventet.
Sammenligning af Løsninger
For at give et klart overblik, er her en tabel, der sammenligner de tre diskuterede metoder.
| Metode | Fordele | Ulemper | Bedst Egnet Til |
|---|---|---|---|
Anførselstegn "$var" | Simpel, POSIX-kompatibel, fundamental god praksis. | Kan føre til andre fejl (f.eks. 'integer expression expected'), hvis datatyper ikke matcher. | Alle scripts, især dem der kræver maksimal portabilitet. |
Dobbelte Parenteser [[...]] | Mere robust, færre faldgruber, understøtter mønstermatchning. | Ikke POSIX-kompatibel (primært til Bash, Zsh, etc.). | Scripts, der specifikt er skrevet til og køres med Bash. |
Eksplicit Tjek -z | Meget robust, giver mulighed for brugerdefinerede fejlmeddelelser, god programmeringsstil. | Kræver mere kode for at håndtere alle tilfælde. | Kritiske scripts hvor inputvalidering er vigtig. |
Ofte Stillede Spørgsmål (FAQ)
Hvorfor ser jeg fejlen med andre operatorer som `-gt` eller `-lt`?
Fejlen er ikke specifik for -eq. Den kan opstå med enhver binær operator (en der kræver to operander) i en [ ... ] test, herunder -ne (ikke lig med), -gt (større end), -lt (mindre end), osv. Årsagen er altid den samme: en af variablerne udvides til ingenting, hvilket efterlader operatoren med en manglende operand.
Er `[[ ... ]]` altid bedre end `[ ... ]`?
For scripts, du ved kun vil blive kørt med Bash, er [[ ... ]] generelt sikrere og mere kraftfuld. Den forhindrer mange almindelige fejl og tilbyder ekstra funktionalitet som regulære udtryk. Men hvis du skriver et script, der skal kunne køre på ethvert system med en POSIX-kompatibel shell (som /bin/sh på mange systemer), skal du holde dig til [ ... ] og omhyggeligt bruge anførselstegn.
Hvordan kan jeg debugge dette problem i mit eget script?
En fantastisk måde at se, hvad der sker, er at køre dit script med -x flaget. Du kan enten ændre shebang-linjen til #!/bin/bash -x eller køre scriptet som bash -x dit_script.sh. Dette vil printe hver kommando til terminalen, lige før den udføres, efter at alle variabler er blevet udvidet. Du vil tydeligt kunne se, at if [ $num1 -eq $num2 ] bliver til + '[' 10 -eq ']', hvilket afslører problemet.
Konklusion
Fejlen unary operator expected er en klassisk faldgrube i Bash-scripting, men den er heldigvis let at forstå og rette, når man først kender årsagen. Den bunder næsten altid i en tom variabel, der skaber syntaktisk rod i en betinget test. Ved at følge de simple, men effektive regler – altid at bruge anførselstegn om dine variabler i [ ... ] tests eller ved at bruge den mere moderne [[ ... ]] syntaks – kan du eliminere denne fejl fra dine scripts. At mestre håndteringen af sådanne fejl er et afgørende skridt på vejen mod at blive en mere kompetent og selvsikker scripter.
Hvis du vil læse andre artikler, der ligner Bash Fejl: Unary Operator Expected Løst, kan du besøge kategorien Sundhed.
