Estoy escribiendo scripts de shell para mi servidor, que es un alojamiento compartido que ejecuta FreeBSD. También quiero poder probarlos localmente, en mi PC con Linux. Por lo tanto, estoy tratando de escribirlos de forma portátil, pero sed
no veo forma de hacerlo.
Parte de mi sitio web utiliza archivos HTML estáticos generados, y esta línea de sed inserta DOCTYPE correcto después de cada regeneración:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Funciona con GNU sed
en Linux, pero FreeBSD sed
espera que el primer argumento después de la -i
opción sea una extensión para la copia de seguridad. Así es como se vería:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Sin embargo, GNU sed
a su vez espera que la expresión siga inmediatamente después -i
. (También requiere correcciones con el manejo de nueva línea, pero eso ya se respondió aquí )
Por supuesto, puedo incluir este cambio en la copia del script de mi servidor, pero eso podría causar problemas, es decir, mi uso de VCS para el control de versiones. ¿Hay alguna manera de lograr esto con sed de una manera totalmente portátil?
-i
Respuestas:
GNU sed acepta una extensión opcional después
-i
. La extensión debe estar en el mismo argumento sin espacio intermedio. Esta sintaxis también funciona en BSD sed.Tenga en cuenta que en BSD,
-i
también cambia el comportamiento cuando hay varios archivos de entrada: se procesan de forma independiente (por ejemplo,$
coincide con la última línea de cada archivo). Además, esto no funcionará en BusyBox.Si no desea utilizar archivos de copia de seguridad, puede verificar qué versión de sed está disponible.
O, alternativamente, para evitar golpear los parámetros posicionales, defina una función.
Si no quieres molestarte, usa Perl.
Si desea escribir un script portátil, no lo use
-i
, no está en POSIX. Haga manualmente lo que sed hace debajo del capó: es solo una línea más de código.fuente
sed -i
también implica-s
. Y la forma más fácil de verificar si hay GNUsed
es con elsed v
comando que es un noop válido para GNU pero falla en cualquier otro lugar.sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file"
si no es GNU sed, inserta un espacio seguido de dos comillas después-i
para que trabaja en BSD. GNU sed obtiene solo-i
.v
comando para probar GNU sed. ¿Qué pasa si FreeBSD decide implementarlo?sed v
dado que ese es su propósito para existir.Si no encuentras un truco para hacer que el
sed
juego sea agradable, puedes intentar:No utilizar
-i
:Usa Perl
fuente
ed
Siempre puede usar
ed
para anteponer una línea a un archivo existente.Detalles
Los bits alrededor del
<!DOCTYPE html>
son comandos paraed
indicarle que agregue esa línea al archivomy.html
.sed
Creo que este comando
sed
también se puede usar:fuente
También puede hacer manualmente lo que
perl -i
hace debajo del capó:Como
perl -i
, no hay copia de seguridad, y como la mayoría de las soluciones dadas aquí, tenga en cuenta que puede afectar los permisos, la propiedad del archivo y puede convertir un enlace simbólico en un archivo normal.Con:
sed
sobrescribiría el archivo sobre sí mismo, por lo que no afectaría la propiedad y los permisos o enlaces simbólicos. Funciona con GNUsed
porquesed
normalmente habrá leído un búfer lleno de datosfile
(4k en mi caso) antes de sobrescribirlo con eli
comando. Eso no funcionaría si el archivo fuera más de 4k, excepto por el hecho de quesed
también amortigua su salida.Básicamente
sed
funciona en bloques de 4k para leer y escribir. Si la línea a insertar es más pequeña que 4k,sed
nunca sobrescribirá un bloque que aún no haya leído.Sin embargo, no contaría con eso.
fuente
echo '<!DOCTYPE html>'
o escapar sin "" comillas.FreeBSD sed , que también se usa en Mac OS X, necesita la
-e
opción después del-i
cambio para definir y reconocer el siguiente comando (regex) correctamente y sin ambigüedades.En otras palabras,
sed -i -e ...
debería funcionar con FreeBSD y GNUsed
.En términos más generales, omitir la extensión de copia de seguridad después de FreeBSD
sed -i
requiere algunased
opción explícita o cambiar siguiendo la-i
para evitar confusiones por parte de FreeBSDsed
mientras analiza sus argumentos de línea de comandos.(Tenga en cuenta, sin embargo, que las
sed
ediciones de archivos en el lugar conducen a cambios en el inodo del archivo, consulte la edición "en el lugar" de los archivos ).(Como pista general, las versiones recientes de FreeBSD
sed
tienen el-r
interruptor para aumentar la compatibilidad con GNUsed
).fuente
bsdsed -i -e 's/a/A/'
es una edición en el lugar, se está editando al guardar el original con un sufijo "-e" ( ).testfile.txt-e
Para emular
sed -i
para un solo archivo de forma portátil, evitando las condiciones de carrera tanto como sea posible:Por cierto, esto también maneja el posible problema que se
sed -i
presenta, ya que, dependiendo de los permisos de directorio y archivo,sed -i
podría permitir que un usuario sobrescriba un archivo que ese usuario no tiene permisos para editar.También puede hacer copias de seguridad como:
fuente
Puede usar Vim en modo Ex:
1
seleccione primera líneai
insertar texto y nueva líneax
guardar y cerrarO incluso, como en los comentarios, el viejo estándar
ex
:fuente
ex
, excepto que las implementaciones no son necesarias para admitir varios-c
indicadores. Para una portabilidad definitiva, usaríaprintf '%s\n' 1i '<!DOCTYPE html>' . x | ex file