Sed con edición in situ cambia la propiedad grupal del archivo

8

Tengo un phpscript de shell ( ) que se pone en contacto con el archivo de destino de esta manera:

  • inspecciona si los archivos y directorios se puede escribir con php's is_writable()(no creo que esto es un problema)
  • edita el archivo en el lugar con el sedcomando:

grep -q "$search" "$passwd_file" && { sed -i "s|$search|$replace|" "$passwd_file"; printf "Password changed!\n"; } || printf "Password not changed!\n"

Como resultado obtengo (todo lo demás correcto pero) el archivo que debía myuser:www-dataser myuser:myuser.

¿ sedCambia la propiedad del grupo de archivos como parece, y cómo puedo evitarlo, si es posible?

Miloš Đakonović
fuente

Respuestas:

16

Hay un pequeño problema con sedel modo de edición in situ -i. sedcrea un archivo temporal en el mismo directorio llamado sedy08qMA, donde y08qMAes una cadena generada aleatoriamente. Ese archivo se llena con el contenido modificado del archivo original. Después de la operación, sedelimina el archivo original y renombra el archivo temporal con el nombre del archivo original. Por lo tanto, no es una verdadera edición in situ . Crea un nuevo archivo con permisos del usuario llamante y un nuevo número de inodo. Ese comportamiento no es malo, pero por ejemplo, los enlaces duros se rompen.

Sin embargo, si desea una verdadera edición in situ, debe usarla ed. Lee los comandos del stdin y edita el archivo directamente, sin un archivo temporal (se realiza sobre edel búfer de memoria). Una práctica común es usar printfpara generar la lista de comandos:

printf "%s\n" '1,$s/search/replace/g' wq | ed -s file

El printfcomando produce resultados de la siguiente manera:

1,$s/search/replace/g
wq

Esas dos líneas son edcomandos. El primero busca la cadena searchy la reemplaza por replace. El segundo escribe ( w) los cambios en el archivo y cierra ( q). -ssuprime la salida de diagnóstico.

caos
fuente
8

El -iparámetro de sedfunciona creando un archivo temporal durante la operación, luego sobrescribe el archivo real con el archivo temporal al final. Esa es la causa más probable del problema, ya que al crear la propiedad del archivo temporal, el valor predeterminado esmyuser:myuser

Puede establecer el setgidbit en el directorio principal (solo si el directorio principal es propiedad del grupo www-data), de modo que los archivos creados en este directorio hereden el mismo grupo.
Para hacer eso:

chmod g+s parent-dir-of-your-file  

Creo que este es un uso muy típico de la setgidbroca.

Dave.d
fuente
@cuonglm Acabo de hacer una secuencia sed -i, encontré la siguiente línea en la traza, ¿significa que creó el archivo temporal en el directorio actual? open("./sedKyG9Ei", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
Dave.d
@DavidDai: Sí, mi mala memoria.
Cuonglm
2

El uso de en edlugar de sedparece bastante superfluo para esto, dado que tiene que canalizar una entrada adicional. La distribución en la que estoy trabajando en este momento (CentOS 5.10) tiene la -copción de sedque utiliza 'copiar' el archivo temporal en lugar de simplemente renombrarlo cuando se usa con la -iopción. Lo probé y funcionó a la perfección, conservando el propietario y el grupo originales al hacer una edición en línea. NO conserva el tiempo de modificación.

p.ej, sed -ci -e '3,5d' file.txt

  • -c utiliza la copia en lugar del cambio de nombre (es decir, conserva la propiedad / grupo)
  • -i edición en línea
  • -e script / expresión a ejecutar

No estoy seguro de cuán extendida está esta opción para sedotras distribuciones. Solaris 10 no lo tenía, pero Solaris no tiene muchas cosas que quiero.

devnulldad
fuente
Suena bastante útil. Sin embargo, no en Ubuntu 14.04, FWIW. :-(
John Rix