En mi script bash, uso find para obtener los nombres de las carpetas mediante comodines:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff ${i} done doStuff() { echo ${1} return ${1}"/hello"; }
El problema es que cuando hago esto, obtengo el siguiente error (digamos que $ {i} corresponden a «home / me / my_directory»):
line 111: "/home/me/my_directory": is a directory.
(la línea 111 es la línea con «doStuff «)
He intentado hacer esto, sin éxito:
for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard}); do stuff=doStuff "${i}" done
Aparentemente es porque el programa está intentando ejecutar el directorio, pero solo lo quiero como una cadena que pueda manipular.
Comentarios
Respuesta
Las citas y la sustitución de comandos son sus problemas aquí.
El problema específico con el que se está encontrando es porque el shell está intentando ejecutar un comando llamado /home/me/my_directory
con la variable de entorno stuff=doStuff
.
Lo que realmente quieres (si» interpreto correctamente) es ejecutar doStuff
con el valor de $i
como argumento, asignando la salida a la variable stuff
. La forma de hacer esto es envolver su comando en $()
. Por ejemplo:
stuff="$(doStuff "$i")"
Observe cómo también pongo comillas alrededor de todo. Esto es para evitar que el shell divida palabras que no quieres que divida (convertirá un solo argumento de /foo/bar baz
en /foo/bar
y baz
).
Además, la salida de su función es lo que se usa como valor de retorno, no return
.
Como debería usar más comillas, también debería agregarlas a todo lo demás. Aquí tienes una versión completa de tu 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
Tienes que poner la definición de la función antes de intentar usarla. Shell no se analiza como los programas compilados, donde pasa por el archivo varias veces. Es de arriba hacia abajo.
También he modificado doStuff
para enviar el echo
a STDERR donde se mostrará en la terminal, y luego printf
lo envía a STDOUT, donde se capturará en la variable stuff
.
Tenga en cuenta que esto seguirá siendo un problema si alguno de sus directorios contiene una nueva línea. Sin embargo, esta es una limitación del shell. El único carácter que una ruta de archivo no puede contiene es un carácter NULL (\0
). Sin embargo, bash y otros shells no pueden almacenar un carácter NULL en una cadena (no todos, pero muchos. Sé que zsh puede), así que puedes » No lo use como delimitador.
Comentarios
- Solo quería agregar eso si tiene espacio antes / después
=
, se estropea. p.ej. MY_VAR = ' / some / path ' es válido pero MY_VAR = ' / some / La ruta ' o MY_VAR = ' / alguna / ruta ' no es
Respuesta
Ese es un buen esfuerzo, pero muestra que está intentando escribir bash
como si fuera un lenguaje de programación, cuando en realidad es un lenguaje de scripting simple. El problema con su construcción stuff=doStuff arg
es que para bash
no significa lo que usted cree que significa. Para bash
, stuff=doStuff
es una asignación de variable y arg
es un comando. Le sugiero que lea los siguientes dos enlaces:
- ¿Cómo puedo almacenar el valor de retorno y / o la salida de un comando en una variable?
- ¿Cómo devuelvo una cadena (o un número grande o un número negativo) de una función? «return» solo me permite dar un número del 0 al 255.
Una versión funcional de algo similar a lo que tienes sería
doStuff () { echo "$1/hello" } stuff=$(doStuff "$i")
Respuesta
La línea que da el error no hace lo que crees que hace:
Primero establece las cosas de la variable de entorno en la cadena «doStuff», y luego intenta ejecutar $ {i} como un comando. Y dado que $ {i} es un directorio, eso falla con el mensaje de error dado.
find "${directory}" -mindepth 1 -type d -name "${wildcard}" -print0 | xargs -0 doStuff
//a wrong bash line comment
en lugar de#a correct bash line comment