Un amigo mío señala que si haces:
perl -pi.bak -e 's/foo/bar/' somefile
cuando "somefile" es en realidad un enlace simbólico, perl hace exactamente lo que dicen los documentos:
Para ello, renombra el archivo de entrada, abre el archivo de salida con el nombre original y selecciona ese archivo de salida como predeterminado para las declaraciones print (). La extensión, si se proporciona, se utiliza para modificar el nombre del archivo antiguo para hacer una copia de seguridad [...]
Lo que da como resultado un nuevo enlace simbólico "somefile.bak" que apunta al archivo real sin cambios, y un nuevo archivo regular "somefile" con los cambios.
En muchos casos, seguir el enlace simbólico sería el comportamiento deseado (incluso si deja ambigua la ubicación correcta del archivo .bak). ¿Hay una manera simple de hacer esto que no sea probar los enlaces simbólicos en un contenedor y manejar el caso adecuadamente?
( sed
hace lo mismo, por lo que vale).
-p -i
en tu guión.Respuestas:
Me pregunto si la pequeña
sponge
utilidad de propósito general ("absorber la entrada estándar y escribir en un archivo") de moreutils será útil en este caso y si seguirá el enlace simbólico.El autor describe
sponge
así:fuente
sponge
para tal uso en la práctica? En cuanto a mí: todavía no. ¿Podría por favor dejar un comentario que indique si se comportó en una prueba como se quería aquí? Oh, veo el comentario. ¡Gracias por la confirmación!file
en su ejemplo anterior hay un enlace simbólico, el enlace se deja solo y el archivo real cambia.Si sabe a
somefile
ciencia cierta que es un enlace simbólico, puede proporcionar explícitamente la ruta completa al archivo con lo siguiente:perl -pi.bak -e 's/foo/bar/' $(readlink somefile)
De esa manera, el enlace simbólico original permanece intacto ya que el reemplazo ahora se realiza directamente con el archivo original.
fuente
readlink
todavía puede ser otro enlace simbólico. Lo mejor sería usar-f
o-e
cuando esté disponible ozsh
's$file:P
o(:P)
calificador global como se muestra en @ikegami para obtener una ruta sin enlace simbólico.Si se trata de un solo archivo que, el comando se vería de la siguiente manera:
La solución entonces es la siguiente:
Esto maneja enlaces simbólicos y no simbólicos.
Si se trata de una cantidad arbitrariamente grande de archivos, el comando se vería de la siguiente manera:
La solución entonces es la siguiente:
Esto maneja enlaces simbólicos y no simbólicos.
La advertencia
readlink
no es un comando estándar, por lo que su presencia, sus argumentos y su funcionalidad varían según el sistema, así que asegúrese de verificar su documentación. Por ejemplo, algunas implementaciones tienen-f
(que también podría usar aquí), pero no-e
, algunas tampoco.busybox
Sereadlink -f
comporta como GNUreadlink -e
. Y algunos sistemas tienen unrealpath
comando en lugar dereadlink
que generalmente se comporta como GNUreadlink -f
.Tenga en cuenta que con GNU
readlink -e
, los enlaces simbólicos que no se pueden resolver a un archivo existente se eliminan silenciosamente.fuente
$var:P
no funciona para mí. (X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'
salidastmp:P
)$var:P
. Con versiones anteriores, siempre puede usar$var:A
en su lugar. Consulte el manual para conocer las diferencias y zsh.org/mla/users/2016/msg00593.html para conocer los motivos de la introducción:P
(larealpath()
interfaz real ).:A
se agregó en 4.3.10 (2009), GNUreadlink -z
en 2012, no conozco ninguna otrareadlink
implementación que admita-z
). Tenga en cuenta que con GNUxargs
, generalmente desea la-r
opción a menos que pueda garantizar que la entrada no estará vacía. Aquí, no es gran cosa (a menos que elperl
código contenga una declaraciónBEGIN
/END
), solo recibiría una-i used with no filenames on the command line, reading from STDIN.
advertencia si eso sucede.-r
la documentación. Pensé que hice lo contrario de lo que hace. Readded