V mém bash skriptu používám find k získání názvů složek pomocí zástupných znaků:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff ${i} done doStuff() { echo ${1} return ${1}"/hello"; }
Problém je v tom, že když to udělám, dostanu následující chyba (řekněme, že $ {i} odpovídá „home / me / my_directory“):
line 111: "/home/me/my_directory": is a directory.
(řádek 111 je řádek s „doStuff“ „)
Zkoušel jsem to udělat, ale marně:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff "${i}" done
Je to zřejmě proto, že se program pokouší spustit adresář, ale chci to pouze jako řetězec, se kterým můžu manipulovat.
Komentáře
odpověď
Zde jsou vaše problémy s citacemi a nahrazením příkazů.
Konkrétní problém, na který narazíte, je ten, že se shell pokouší spustit příkaz s názvem /home/me/my_directory
s proměnnou prostředí stuff=doStuff
.
To, co opravdu chcete (pokud interpretuji správně) je spustit doStuff
s hodnotou $i
jako argumentu, který přiřadí výstup proměnné stuff
. Způsob, jak toho dosáhnout, je zabalit příkaz do $()
. Například:
stuff="$(doStuff "$i")"
Všimněte si, jak také kolem všeho uvádím uvozovky. To zabrání tomu, aby shell rozdělil věci, které nechcete rozdělit na slovo (promění jeden argument /foo/bar baz
na /foo/bar
a baz
).
Výstupem vaší funkce je také to, co se použije jako návratová hodnota, nikoli return
.
Protože byste měli používat více uvozovek, měli byste je také přidat ke všem ostatním. Zde je úplná verze vašeho skriptu:
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
Před použitím funkce musíte definici funkce vložit. Shell není analyzován jako kompilované programy, kde prochází souborem několikrát. Je shora dolů.
Upravil jsem také doStuff
tak, aby odeslal echo
do STDERR, kde se zobrazí na terminálu, a poté printf
odešle do STDOUT, kde bude zachycen do proměnné stuff
.
Všimněte si, že to bude mít problém, pokud některý z vašich adresářů obsahuje nový řádek. Jedná se však o omezení prostředí. Jediný znak, k němuž cesta k souboru nemůže contain je NULL char (\0
). Nicméně bash a jiné shelly nemohou uložit NULL char do řetězce (ne všechny, ale mnoho. Vím, že zsh může), takže můžete “ nepoužívejte jej jako oddělovač.
Komentáře
- Chtěl jsem jen dodat, že pokud máte mezeru před / po
=
to pokazí. např. MY_VAR = ' / some / path ' je platný, ale MY_VAR = ' / some / cesta ' nebo MY_VAR = ' / some / path ' není
Odpověď
To je dobré úsilí, ale ukazuje to, že se snažíte napsat bash
jako by to byl programovací jazyk, když je to vlastně jednoduchý skriptovací jazyk. Problém s vaší stuff=doStuff arg
konstrukcí spočívá v tom, že to pro bash
neznamená to, co si myslíte, že to znamená. K bash
je stuff=doStuff
přiřazení proměnné a arg
je příkaz. Doporučuji přečíst následující dva odkazy:
- Jak mohu uložit návratovou hodnotu a / nebo výstup příkazu do proměnné?
- Jak vrátím řetězec (nebo velké číslo nebo záporné číslo) z funkce? „návrat“ mi umožňuje pouze zadat číslo od 0 do 255.
Pracovní verze něčeho podobného tomu, co máte, by byla
doStuff () { echo "$1/hello" } stuff=$(doStuff "$i")
Odpověď
Řádek udávající chybu nedělá to, co si myslíte:
Nejprve nastaví proměnné prostředí na řetězec „doStuff“ a poté se pokusí provést příkaz $ {i} jako příkaz. A protože $ {i} je adresář, který s danou chybovou zprávou selže.
find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
//a wrong bash line comment
místo#a correct bash line comment