Nel mio script bash, utilizzo find per ottenere i nomi delle cartelle con caratteri jolly:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff ${i} done doStuff() { echo ${1} return ${1}"/hello"; }
Il problema è che quando lo faccio, ottengo il seguente errore (diciamo che $ {i} corrisponde a “home / me / my_directory”):
line 111: "/home/me/my_directory": is a directory.
(la riga 111 è la riga con “doStuff “)
Ho” provato a farlo, inutilmente:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff "${i}" done
Apparentemente è perché il programma sta cercando di eseguire il directory, ma lo voglio solo come una stringa che posso manipolare.
Commenti
Risposta
Le virgolette e la sostituzione dei comandi sono i tuoi problemi qui.
Il problema specifico che stai riscontrando è perché la shell sta cercando di eseguire un comando chiamato /home/me/my_directory
con la variabile di ambiente stuff=doStuff
.
Quello che vuoi veramente (se” sto interpretando correttamente) è eseguire doStuff
con il valore di $i
come argomento, assegnando loutput alla variabile stuff
. Il modo per farlo è racchiudere il comando in $()
. Ad esempio:
stuff="$(doStuff "$i")"
Nota come ho anche messo virgolette intorno a tutto. Questo serve per evitare che la shell divida in parole cose che non vuoi che divida in parole (trasformerà un singolo argomento di /foo/bar baz
in /foo/bar
e baz
).
Anche loutput della tua funzione è ciò che viene utilizzato come valore di ritorno, non return
.
Dato che dovresti usare più virgolette, dovresti anche aggiungerle a tutto il resto. Ecco una versione completa del tuo 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
Devi inserire la definizione della funzione prima di provare ad usarla. La shell non viene analizzata come i programmi compilati, dove passa attraverso il file più volte. È top-down.
Ho anche modificato doStuff
per inviare il echo
a STDERR dove verrà mostrato sul terminale, quindi printf
invia a STDOUT dove verrà catturato nella variabile stuff
.
Nota che questo avrà ancora un problema se una qualsiasi delle tue directory contiene una nuova riga. Tuttavia questa è una limitazione della shell. Lunico carattere che un percorso di file non può contenere è un carattere NULL (\0
). Tuttavia bash e altre shell non possono memorizzare un carattere NULL in una stringa (non tutti, ma molti. So che zsh può), quindi puoi ” t usarlo come delimitatore.
Commenti
- Volevo solo aggiungerlo se hai spazio prima / dopo
=
, si incasina. per esempio. MY_VAR = ' / some / path ' è valido ma MY_VAR = ' / some / path ' o MY_VAR = ' / some / path ' non è
Risposta
È un buon lavoro ma mostra che stai cercando di scrivere bash
come se fosse un linguaggio di programmazione, quando in realtà è un semplice linguaggio di scripting. Il problema con la tua costruzione stuff=doStuff arg
è che bash
non significa ciò che pensi significhi. Per bash
, stuff=doStuff
è unassegnazione di variabile e arg
è un comando. Ti suggerisco di leggere i seguenti due link:
- Come posso memorizzare il valore di ritorno e / o loutput di un comando in una variabile?
- Come restituisco una stringa (o un numero grande o un numero negativo) da una funzione? “return” mi consente di fornire solo un numero compreso tra 0 e 255.
Una versione funzionante di qualcosa di simile a quello che hai tu sarebbe
doStuff () { echo "$1/hello" } stuff=$(doStuff "$i")
Risposta
La riga che dà lerrore non fa quello che pensi:
Per prima cosa imposta la variabile dambiente roba sulla stringa “doStuff”, quindi cerca di eseguire $ {i} come comando. E poiché $ {i} è una directory, fallisce con il messaggio di errore fornito.
find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
//a wrong bash line comment
invece di#a correct bash line comment