In mijn bash-script gebruik ik find om de mapnamen met jokertekens te krijgen:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff ${i} done doStuff() { echo ${1} return ${1}"/hello"; }
Het probleem is dat wanneer ik dit doe, ik de volgende foutmelding (laten we zeggen dat $ {i} overeenkomt met “home / me / mijn_directory”):
line 111: "/home/me/my_directory": is a directory.
(regel 111 is de regel met “doStuff “)
Ik heb dit geprobeerd, maar het mocht niet baten:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff "${i}" done
Blijkbaar is het omdat het programma probeert de directory, maar ik wil het gewoon als een string die ik kan manipuleren.
Reacties
Antwoord
Aanhalingstekens en vervanging van commandos zijn hier uw problemen.
Het specifieke probleem dat u “tegenkomt, is omdat de shell een commando probeert uit te voeren met de naam /home/me/my_directory
met de omgevingsvariabele stuff=doStuff
.
Wat je echt wilt (als ik” m correct interpreteer) is om doStuff
met de waarde $i
als argument, waarbij de uitvoer wordt toegewezen aan de variabele stuff
. De manier om dit te doen is door uw commando in $()
te plaatsen. Bijvoorbeeld:
stuff="$(doStuff "$i")"
Let op hoe ik ook overal aanhalingstekens plaats. Dit is om te voorkomen dat de shell dingen opsplitst die je niet wilt dat het woord splitst (het “zal een enkel argument van /foo/bar baz
veranderen in /foo/bar
en baz
).
Ook de output van je functie is wat wordt gebruikt als de retourwaarde, niet return
.
Omdat je meer aanhalingstekens zou moeten gebruiken, zou je ze ook aan al het andere moeten toevoegen. Hier is een volledige versie van uw script:
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
U moet de functiedefinitie plaatsen voordat u deze probeert te gebruiken. Shell wordt niet geparseerd zoals gecompileerde programmas, waar het meerdere keren door het bestand gaat. Het is van boven naar beneden.
Ik heb ook doStuff
gewijzigd om de echo
naar STDERR waar het op de terminal getoond zal worden, en vervolgens stuurt de printf
naar STDOUT waar het wordt vastgelegd in de variabele stuff
.
Merk op dat dit nog steeds een probleem zal hebben als een van uw mappen een nieuwe regel bevat. Dit is echter een beperking van de shell. Het enige teken dat een bestandspad niet kan contain is een NULL-teken (\0
). Bash en andere shells kunnen echter geen NULL-teken in een string opslaan (niet alle, maar veel. Ik weet dat zsh kan), dus je kunt ” gebruik het niet als scheidingsteken.
Opmerkingen
- Ik wilde dat alleen toevoegen als je ruimte voor / na
=
, het maakt een fout. bijv. MY_VAR = ' / some / path ' is geldig maar MY_VAR = ' / some / pad ' of MY_VAR = ' / sommige / pad ' is niet
Antwoord
Dat is een goede poging, maar het laat zien dat je probeert bash
alsof het een programmeertaal is, terwijl het eigenlijk een eenvoudige scripttaal is. Het probleem met je stuff=doStuff arg
constructie is dat bash
het niet betekent wat je denkt dat het betekent. Aan bash
, stuff=doStuff
is een variabeletoewijzing en arg
is een commando. Ik stel voor dat je de volgende twee links leest:
- Hoe kan ik de retourwaarde en / of uitvoer van een commando in een variabele opslaan?
- Hoe retourneer ik een string (of een groot getal of een negatief getal) van een functie? “return” laat me alleen een getal tussen 0 en 255 geven.
Een werkende versie van iets dat lijkt op wat je hebt, zou zijn
doStuff () { echo "$1/hello" } stuff=$(doStuff "$i")
Answer
De regel met de fout doet niet wat je denkt dat hij doet:
Het stelt eerst de omgevingsvariabele stuff in op de string “doStuff”, en probeert vervolgens $ {i} uit te voeren als een commando. En aangezien $ {i} een directory is, mislukt dat met de gegeven foutmelding.
find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
//a wrong bash line comment
in plaats van#a correct bash line comment