Uso Bash 4.3.48(1) en Ubuntu 16.04 (xenial) con una pila LEMP.
Intento crear un php.ini
anula el archivo de forma independiente de la versión con printf
.
printf "[PHP]n post_max_size = 200Mn upload_max_filesize = 200Mn cgi.fix_pathinfo = 0" > /etc/php/*/fpm/zz_overrides.ini
Se da el siguiente error:
bash:/etc/php/*/zz_overrides.ini:No existe tal archivo o directorio
printf "[PHP]n post_max_size = 200Mn upload_max_filesize = 200Mn cgi.fix_pathinfo = 0" > /etc/php/7.0/fpm/zz_overrides.ini
Como puede ver, ambos son básicamente idénticos además de *
frente a 7.0
.
- No encontré ninguna pista sobre este problema (¿regex?) en
man printf
. - Busqué en Google y no encontré nada sobre "permitir expresiones regulares en printf".
¿Por qué falla la operación independiente de la versión y hay alguna omisión?
Editar:Si es posible, es más importante para mí usar una operación de una línea.
Respuesta aceptada:
El comportamiento de una coincidencia de patrón en una redirección parece diferir entre shells. De los que hay en mi sistema, dash y ksh93 no expanden el patrón, por lo que obtienes un nombre de archivo con un literal *
. Bash lo expande, pero solo si el patrón coincide con un archivo. Se queja si hay más nombres de archivo que coincidan. Zsh funciona como si hubiera dado múltiples redirecciones, redirige la salida a todos archivos coincidentes.
(1) excepto cuando no es interactivo y está en modo POSIX
Si desea que la salida vaya a todos los archivos coincidentes, puede usar tee
:
echo ... | tee /path/*/file > /dev/null
Si quieres que vaya a un solo archivo, el problema es decidir cuál usar. Si desea verificar que solo hay un archivo que coincida con el patrón, expanda la lista completa y cuéntelos.
En bash/ksh:
names=(/path/*/file)
if [ "${#names[@]}" -gt 1 ] ; then
echo "there's more than one"
else
echo "there's only one: ${names[0]}"
fi
En shell estándar, set
los parámetros posicionales y usa $#
para el conteo.
Por supuesto, si el patrón no coincide con ningún archivo, se deja como está y, dado que el globo está en el medio, el resultado apunta a un directorio que no existe. Es lo mismo que intentar crear /path/to/file
, antes de /path/to
existe, es solo que aquí tenemos /path/*
en cambio, literalmente, con el asterisco.
Para lidiar con eso, tendría que expandir los nombres de los directorios sin el nombre del archivo y luego agregar el nombre del archivo a todos los directorios. Esto es un poco feo…
dirs=(/path/*)
files=( "${dirs[@]/%//file}" )
y luego podemos usar esa matriz:
echo ... | tee "${files[@]}" > /dev/null
O podríamos tomar el camino fácil y recorrer el patrón de nombre de archivo. Es un poco insatisfactorio en el caso más general, ya que requiere ejecutar el comando principal una vez para cada archivo de salida o usar un archivo temporal para almacenar la salida.
for dir in /path/* ; do
echo ... > "$dir/file"
done