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
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:
- Hvordan kan jeg lagre returverdien og / eller utgangen til en kommando i en variabel?
- Hvordan returnerer jeg en streng (eller et stort tall eller et negativt tall) fra en funksjon? «retur» lar meg bare gi et tall fra 0 til 255.
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.
find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
//a wrong bash line comment
i stedet for#a correct bash line comment