GNU/Linux >> Tutoriales Linux >  >> Linux

¿La redirección a un nombre de archivo global falla?

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 .

1) La operación independiente de la versión falla:

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

2) La operación gnóstica de la versión tiene éxito:

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 

Linux
  1. ¿Redirigir al mismo archivo que el archivo de origen procesado por el comando?

  2. ¿Crear un archivo vacío con un nombre de variable en un script?

  3. Grep no puede encontrar texto en este archivo?

  4. wget:nombre del archivo descargado

  5. mkdir -p falla cuando existe un directorio

Redirección de Bash explicada con ejemplos

Shell Scripting Parte 4:entrada, salida y redirección

¿Cómo sé el nombre del archivo de script en un script Bash?

Eliminar un enlace simbólico a un directorio

¿Cómo eliminar un archivo con un nombre extraño?

cp -L frente a cp -H