' er en katalog ' feil når du prøver å overføre katalognavn til funksjon

I bash-skriptet mitt bruker jeg finne for å få mappenavnene med jokertegn:

for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff ${i} done doStuff() { echo ${1} return ${1}"/hello"; } 

Problemet er at når jeg gjør dette, får jeg følgende feil (la oss si at $ {i} tilsvarer «hjem / meg / min_katalog»):

line 111: "/home/me/my_directory": is a directory. 

(linje 111 er linjen med «doStuff «)

Jeg har prøvd å gjøre dette, til ingen nytte:

for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff "${i}" done 

Det er tilsynelatende fordi programmet prøver å utføre katalog, men jeg vil bare ha den som en streng som jeg kan manipulere.

Kommentarer

  • Hmmm …. I følge bash man-siden. … Den innebygde kommandoen for retur i bash brukes til å returnere en EXIT-kode (heltall), ikke noen type strengparameter.
  • Du kan også prøve find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
  • googlere : en annen flott kilde for å få denne feilmeldingen ge er //a wrong bash line comment i stedet for #a correct bash line comment

Svar

Sitater og kommandosubstitusjon er problemene dine her.

Det spesifikke problemet du kjører på er fordi skallet prøver å kjøre en kommando kalt /home/me/my_directory med miljøvariabelen stuff=doStuff.
Det du virkelig vil ha (hvis jeg tolker riktig) er å kjøre doStuff med verdien $i som argument, og tilordner utgangen til variabelen stuff. Måten å gjøre dette på er å pakke inn kommandoen din i $(). For eksempel:

stuff="$(doStuff "$i")" 

Legg merke til hvordan jeg også setter anførselstegn rundt alt. Dette er for å forhindre at skallet orddeler ting du ikke vil at det skal deles i ord (det vil gjøre et enkelt argument på /foo/bar baz til /foo/bar og baz).

Også utgangen av funksjonen din er det som blir brukt som returverdi, ikke return.

Ettersom du burde brukt flere anførselstegn, bør du også legge dem til alt annet. Her er en komplett versjon av skriptet ditt:

doStuff() { echo "${1}" >&2 printf "%s/hello" "$1"; } IFS=$"\n" for i in $(find "${directory}" -mindepth 1 -type d -name "${wildcard}"); do stuff="$(doStuff "${i}")" done 

Du må sette funksjonsdefinisjonen før du prøver å bruke den. Shell er ikke analysert som kompilerte programmer, der den går gjennom filen flere ganger. Det er ovenfra og ned.
Jeg har også endret doStuff for å sende echo til STDERR hvor den vil bli vist på terminalen, og deretter sender printf til STDOUT hvor den blir fanget inn i variabelen stuff.

Merk at dette fortsatt vil ha et problem hvis noen av katalogene dine inneholder en ny linje. Dette er imidlertid en begrensning av skallet. Det eneste tegnet en filbane ikke kan inneholder er en NULL-tegn (\0). Imidlertid kan bash og andre skjell ikke lagre en NULL-røye i en streng (ikke alle, men mange. Jeg vet at zsh kan), så du kan » t bruk den som skilletegn.

Kommentarer

  • Ville bare legge til at hvis du har plass før / etter =, det roter til. f.eks. MY_VAR = ' / some / path ' er gyldig, men MY_VAR = ' / some / sti ' eller MY_VAR = ' / some / path ' er ikke

Svar

Det er en god innsats, men det viser at du prøver å skrive bash som om det var et programmeringsspråk, når det faktisk er et enkelt skriptspråk. Problemet med stuff=doStuff arg -konstruksjonen er at for bash betyr det ikke hva du tror det betyr. Til bash er stuff=doStuff en variabel tildeling, og arg er en kommando. Jeg foreslår at du leser følgende to lenker:

En fungerende versjon av noe som ligner på det du har, ville være

doStuff () { echo "$1/hello" } stuff=$(doStuff "$i") 

Svar

Linjen som gir feilen gjør ikke det du tror den gjør:

Den setter først miljøvariabelen til strengen «doStuff», og prøver deretter å utføre $ {i} som en kommando. Og siden $ {i} er en katalog, mislykkes den med den gitte feilmeldingen.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *