linux - El comando sed con la opción-i(edición in situ) funciona bien en Ubuntu, pero no en Mac
macos bsd (4)
En OS X, puede usar la versión GNU de sed: gsed
.
# if using brew
brew install gnu-sed
#if using ports
sudo port install gsed
Entonces, si su script debe ser portable, dependiendo de su sistema operativo, puede definir qué comando usar.
SED=sed
unamestr=`uname`
if [[ "$unamestr" == "Darwin" ]] ; then
SED=gsed
type $SED >/dev/null 2>&1 || {
echo >&2 "$SED it''s not installed. Try: brew install gnu-sed" ;
exit 1;
}
fi
# here your sed command, e.g.:
$SED -i "/ $domain .*#drupalpro/d" /etc/hosts
Esta pregunta ya tiene una respuesta aquí:
No sé nada de Sed, pero necesito este comando (que funciona bien en Ubuntu) para trabajar en Mac OSX:
sed -i "/ $domain .*#drupalpro/d" /etc/hosts
Me estoy poniendo:
sed: 1: "/etc/hosts": extra characters at the end of h command
Para complementar la respuesta útil y precisa de microtherion :
- con una solución portátil
- con información de fondo
tl; dr :
El equivalente de este comando GNU sed
(estándar en la mayoría de las distros Linux ):
sed -i ''s/foo/bar/'' file
es este comando BSD / macOS sed
:
sed -i '''' ''s/foo/bar/'' file # Note the '''' as a *separate argument*
Con BSD / macOS sed
, los siguientes comandos no funcionan del todo o no como se esperaba:
sed -i ''s/foo/bar/'' file # Breaks; script is misinterpreted as backup-file suffix
sed -i'''' ''s/foo/bar/'' file # Ditto
sed -i -e ''s/foo/bar/'' file # -e is misinterpreted as backup-file suffix
Para una discusión de todas las diferencias entre GNU sed
y BSD / macOS sed
, vea esta respuesta mía.
Enfoque portátil :
Nota: Portátil aquí significa que el comando funciona con ambas implementaciones discutidas. No es portátil en un sentido POSIX , porque la opción -i
no es compatible con POSIX .
# Works with both GNU and BSD/macOS Sed, due to a *non-empty* option-argument:
# Create a backup file *temporarily* and remove it on success.
sed -i.bak ''s/foo/bar/'' file && rm file.bak
Para una explicación, mira a continuación; para soluciones alternativas, incluyendo una que cumpla con POSIX, vea esta respuesta relacionada mía.
Información de fondo
En GNU sed
(estándar en la mayoría de las distribuciones de Linux) y BSD / macOS sed
, la opción -i
, que realiza la actualización in situ [1] de sus archivos de entrada, acepta una opción-argumento que especifica qué sufijo (extensión de nombre de archivo) usar para el archivo de copia de seguridad del archivo que se está actualizando .
Por ejemplo, en ambas implementaciones, lo siguiente mantiene el archivo original, file
, como archivo de respaldo file.bak
:
sed -i.bak ''s/foo/bar/'' file # Keep original as ''file.bak''; NO SPACE between -i and .bak
Aunque con GNU sed
el argumento de sufijo es opcional , mientras que con BSD / macOS sed
es obligatorio , la sintaxis anterior funciona con ambas implementaciones, ya que directamente junto al argumento de opción ( .bak
) a la opción ( -i
) - -i.bak
, a diferencia de -i .bak
- funciona como opción-argumento opcional y obligatorio :
- Sintaxis
-i.bak
es la única forma que funciona para una opción opcional -argumento. - La sintaxis
-i.bak
también funciona como un argumento-opción obligatorio , como una alternativa a-i .bak
, es decir, especificando la opción y su argumento por separado .
No especificar un sufijo , que a menudo es el caso, significa que no se debe guardar ningún archivo de copia de seguridad , y es allí donde surge la incompatibilidad :
Con GNU
sed
, no especificar un sufijo significa simplemente usar-i
solo .Con BSD / macOS
sed
, no especificar un sufijo significa especificar la cadena vacía como el sufijo - obligatorio - y, por razones técnicas , la cadena vacía solo se puede pasar como un argumento separado : es decir,-i ''''
no-i''''
.
-i''''
no funciona, porque para sed
es indistinguible de solo -i
, porque el shell efectivamente elimina las comillas vacías (concatena -i
y ''''
y elimina las comillas con función sintáctica), y pasa solo -i
en ambos casos.
Con (efectivamente) solo -i
especificado, es el siguiente argumento que se interpreta como el argumento de opción:
sed -i ''s/foo/bar/'' file # BREAKS with BSD/macOS Sed
''s/foo/bar/''
- destinado a la secuencia de comandos de Sed (comando) - ahora se interpreta como el sufijo , y el file
palabra se interpreta como la secuencia de comandos.
Interpretar tal palabra como script conduce a un mensaje de error oscuro como
sed: 1: "file": invalid command code f
,
porque f
se interpreta como un comando Sed (función).
Del mismo modo, con:
sed -i -e ''s/foo/bar/'' file # CREATES BACKUP FILE ''file-e''
-e
se interpreta como el argumento de sufijo , y NO como la opción -e
de Sed (que se puede usar para especificar varios comandos, si es necesario).
Como resultado, en lugar de no mantener ninguna copia de seguridad, obtiene un archivo de copia de seguridad con el sufijo -e
.
El hecho de que este comando no funcione como está previsto es menos obvio, porque la actualización in situ tiene éxito, dado que el argumento -e
satisface el requisito de sintaxis del argumento de sufijo.
Que la creación accidental de estos archivos de copia de seguridad pase desapercibida es la explicación más probable para la respuesta incorrecta de Crt y esta respuesta incorrecta a una pregunta similar que recibió tantas votaciones (a partir de este escrito).
[1] Estrictamente hablando, se crea un archivo temporal detrás de escena que luego reemplaza el archivo original; este enfoque puede ser problemático: ver la mitad inferior de esta respuesta mía.
Ubuntu se envía con GNU sed
, donde el sufijo para la opción -i
es opcional. OS X se envía con BSD sed
, donde el sufijo es obligatorio. Prueba sed -i ''''
el hombre es tu amigo
OS X
-i extension
Edit files in-place, saving backups with the specified extension.
If a zero-length extension is given, no backup will be saved. It
is not recommended to give a zero-length extension when in-place
editing files, as you risk corruption or partial content in situ-
ations where disk space is exhausted, etc.