tipos - ¿Por qué los delimitadores alternativos no funcionan con sed-e ''/ pattern/s/a/b/''?
sed shell (5)
Esta pregunta ya tiene una respuesta aquí:
Aquí hay algo que he descubierto que no tiene sentido.
Salida de cat config.h
:
define somevar foo // Sample variable
Esta versión del comando funciona para cambiar foo a bar y preservar los comentarios:
sed -e ''/somevar/s/foo/bar/'' config.h
Esto no funciona:
sed -e ''|somevar|s|foo|bar|'' config.h
Da este error:
sed: -e expresión # 1, char 1: comando desconocido: `| ''
Curiosamente, esto funciona:
sed -e ''/somevar/s|foo|bar|'' config.h
Quizás me esté faltando alguna parte de la documentación. Parece muy extraño tener dos delimitadores diferentes en el mismo comando sed.
¿Error o característica?
Absolutamente puede usar delimitadores alternativos para la dirección coincidente ( /regex/
), pero necesita decirle a sed
que tiene la intención de hacer coincidir con ese delimitador. La forma en que lo haces es con una barra invertida inicial /
. Entonces tu orden puede ser:
sed -e ''/|somevar|s|foo|bar|'' config.h
o simplemente con la misma facilidad:
sed -e ''/%somevar%s|foo|bar|'' config.h
Referencia: POSIX referencia para sed
Característica. En
sed -e ''/somevar/s/foo/bar/'' config.h
El /somevar/
es una dirección . Las direcciones deben ser distinguibles de otras funciones, como y
(yank), i
(insert), a
(append) y muchas más. En general, los comandos sed se analizan como
[address[,address]]function[arguments]
Esto funcionará:
sed -e ''/|somevar|s|foo|bar|''
La página del man
de GNU sed es bastante clara al respecto:
/regexp/
Match lines matching the regular expression regexp.
/cregexpc
Match lines matching the regular expression regexp. The c may
be any character.
Es decir, la c
puede ser cualquier carácter, pero el inicio es obligatorio.
No tengo FreeBSD, pero de acuerdo con @bonsaiviking la página del man
también es muy clara:
El delimitador de apertura debe ir precedido por una barra invertida, a menos que sea una barra diagonal.
Por otro lado, en OSX esto no está claro en absoluto:
In a context address, any character other than a backslash (``/''')
or newline character may be used to delimit the regular expression.
Also, putting a backslash character before the delimiting character
causes the character to be treated literally. For example, in the
context address /xabc/xdefx, the RE delimiter is an ``x'''' and the
second ``x'''' stands for itself, so that the regular expression is
``abcxdef''''.
Observe que el ejemplo allí usa /xpatternx
lugar de solo xpatternx
. Esa es toda la pista que da, no deja claro que xpatternx
no funcionará.
Basado en el argumento de @that-other-guy , tiene sentido que sed
(y otros idiomas como perl
como @Birei señaló @Birei ) necesitan esta pista adicional para funcionar correctamente.
Mi voto es para la función .
Son dos comandos diferentes, el de búsqueda /.../
y el de sustitución, s/.../.../
. Por lo que sé, solo permite cambiar el separador del comando de sustitución.
En perl es similar. Puede realizar una búsqueda de expresiones regulares con /.../
pero si desea cambiar el separador, debe marcarlo explícitamente como una búsqueda con la m
, como: m|...|
.
Supongo que estará relacionado con algún problema de análisis léxico, pero no sé la razón, sin embargo.
Permitir diferentes delimitadores para /pattern/
introduciría la ambigüedad de análisis.
¿ ispaghetti
supone que ispaghetti
es como /spaghett/
, o se supone que debe insertar texto como i spaghetti
?
Con y
no hay tal ambigüedad. Cuando ve cualquiera de esos caracteres, conoce el comando que está leyendo y luego puede interpretar el siguiente carácter como un delimitador.
Podríamos resolver esta ambigüedad para /pattern/
si lo empezáramos con un carácter similarmente reconocible, y de hecho sed tiene un especificador de dirección separado para esto: barra diagonal inversa, como en /|pattern|
(esto no es lo mismo que escapar).
Por lo tanto, podemos escribir /|pattern|s|foo|bar|
.
La dirección y los comandos de edición son independientes, por lo que /$pattern$s_foo_bar_
y /pattern/s#foo#bar#
funcionan.