În scriptul meu bash, folosesc find pentru a obține numele folderelor prin metacaracter:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff ${i} done doStuff() { echo ${1} return ${1}"/hello"; }
Problema este că atunci când fac acest lucru, primesc următoarea eroare (să spunem că $ {i} corespunde „home / me / my_directory”):
line 111: "/home/me/my_directory": is a directory.
(linia 111 este linia cu „doStuff „)
Am încercat să fac acest lucru, fără rezultat:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff "${i}" done
Se pare că programul încearcă să execute director, dar îl vreau doar ca un șir pe care îl pot manipula.
Comentarii
Răspuns
Citatele și înlocuirea comenzilor sunt problemele dvs. aici.
Problema specifică în care vă confruntați este că shell-ul încearcă să ruleze o comandă numită /home/me/my_directory
cu variabila de mediu stuff=doStuff
.
Ceea ce doriți cu adevărat (dacă” interpretez corect) este să rulați doStuff
cu valoarea $i
ca argument, atribuind ieșirea variabilei stuff
. Modalitatea de a face acest lucru este să vă înfășurați comanda în $()
. De exemplu:
stuff="$(doStuff "$i")"
Observați cum pun și ghilimele în jurul tuturor. Acest lucru este pentru a preveni shell-ul de a împărți cuvintele pe care nu doriți să le împartă cuvintele (va transforma un singur argument al /foo/bar baz
în /foo/bar
și baz
).
De asemenea, rezultatul funcției dvs. este ceea ce se folosește ca valoare returnată, nu return
.
Deoarece ar trebui să utilizați mai multe ghilimele, ar trebui să le adăugați și la orice altceva. Iată o versiune completă a scriptului dvs.:
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
Trebuie să puneți definiția funcției înainte de a încerca să o utilizați. Shell nu este analizat ca programele compilate, unde trece prin fișier de mai multe ori. Este de sus în jos.
De asemenea, am modificat doStuff
pentru a trimite echo
către STDERR unde va fi afișat pe terminal, apoi printf
trimite către STDOUT unde va fi capturat în variabila stuff
.
Rețineți că acest lucru va avea în continuare o problemă dacă oricare dintre directoarele dvs. conține o linie nouă. Cu toate acestea, aceasta este o limitare a shell-ului. Singurul caracter pe care calea unui fișier nu îl poate contain este un NULL char (\0
). Cu toate acestea, bash și alte shell-uri nu pot stoca un NULL char într-un șir (nu toate, dar multe. Știu că zsh poate), așa că puteți ” nu îl folosiți ca delimitator.
Comentarii
- Am vrut doar să adăugăm asta dacă aveți spațiu înainte / după
=
, se încurcă. de exemplu. MY_VAR = ' / some / path ' este valid, dar MY_VAR = ' / some / calea ' sau MY_VAR = ' / unele / calea ' nu este
Răspuns
Acesta este un efort bun, dar arată că încercați să scrieți bash
ca și cum ar fi un limbaj de programare, atunci când este de fapt un limbaj de scriptare simplu. Problema cu construcția dvs. stuff=doStuff arg
este că pentru bash
nu înseamnă ce credeți că înseamnă. Pentru bash
, stuff=doStuff
este o atribuire variabilă, iar arg
este o comandă. Vă sugerez să citiți următoarele două linkuri:
- Cum pot stoca valoarea returnată și / sau ieșirea unei comenzi într-o variabilă?
- Cum returnez un șir (sau un număr mare sau un număr negativ) dintr-o funcție? „returnare” îmi permite doar să dau un număr de la 0 la 255.
O versiune funcțională a ceva similar cu ceea ce aveți ar fi
doStuff () { echo "$1/hello" } stuff=$(doStuff "$i")
Răspuns
Linia care dă eroarea nu face ceea ce crezi că face:
Setează mai întâi variabilele de mediu pe șirul „doStuff” și apoi încearcă să execute $ {i} ca comandă. Și din moment ce $ {i} este un director, acesta eșuează cu mesajul de eroare dat.
find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
//a wrong bash line comment
în loc de#a correct bash line comment