Expresión regular entre comillas simples: ¿pierden su valor?

Expresión regular entre comillas simples: ¿pierden su valor?

El libro que estoy leyendo: Learning the Bash Shell de O'Reilly especifica algún código de la siguiente manera:

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

   howmany=$1

   shift
   ....
   ....
   etc

Esto utiliza la greputilidad de búsqueda para probar si $1coincide con el patrón apropiado. Para hacer esto, proporcionamos la expresión regular ^-[0-9][0-9]*$grep, que se interpreta como "un guión inicial seguido de un dígito, seguido opcionalmente de uno o más dígitos". Si se encuentra una coincidencia, grepse devolverá la coincidencia y la prueba será verdadera; de lo contrario, grepno se devolverá nada y el procesamiento pasará a la elifprueba.

Observe que hemos incluido la expresión regular entre comillas simples para evitar que el shell interprete $ y *, y los pasamos a grep sin modificar.

Entonces, ¿por qué la expresión regular no '^-[0-9]'pierde su significado como entre comillas simples? Normalmente, todo lo que está entre comillas simples pierde su significado.

Gracias por su ayuda.

Respuesta1

Mientras otros han respondido a su pregunta específica, agregaré eso

if [ -n "$(echo $1 | grep '^-[0-9][0-9]*$')" ]; then 

Es una forma incorrecta de comprobar si una cadena coincide con una expresión regular por varios motivos:

  1. No se puede utilizar echopara datos arbitrarios.
  2. Dejar una expansión de parámetro sin comillas como la $1anterior es el operador split+glob.
  3. grepno compara la expresión regular con su entrada completa, sino con cada línea de su entrada. Entonces volvería verdadero, foo\n-0\nbarpor ejemplo.
  4. Una expresión regular puede coincidir con una longitud cero, por lo que en el caso general es incorrecto verificar si grepproduce algún resultado (tenga en cuenta que la sustitución de comandos elimina los caracteres de nueva línea finales). Es mejor utilizarlo grep -qy confiar en el estado de salida de grep, en lugar de en el de [, y también evitar la sustitución de comandos.
  5. Tenga en cuenta que ese grepcomando se puede simplificar agrep -xE '-[0-9]+'

bashy ksh93tener zshun operador dedicado para la coincidencia de expresiones regulares (extendidas). Para usarlo de forma portátil y confiable en los tres (y en bash-3.1), la sintaxis es:

re='^-[0-9]+$'
if [[ $1 =~ $re ]]; then
  echo matches
fi

yashy zshtambién soporte:

if [ "$1" '=~' '^-[0-9]+$' ]; then
  echo matches
fi

El comando estándar para hacer coincidencias de expresiones regulares de cadenas (básicas) es expr:

if expr " $1" : ' -[0-9]\{1,\}$' > /dev/null; then
  echo matches
fi

Tenga en cuenta que ^(pero no $) está implícito en expr. También usamos ese carácter de espacio inicial para evitar problemas con valores de $1que resultan ser exproperadores.

También tenga en cuenta que si la expresión regular contiene \(...\), afectará el comportamiento de expr.

Considerándolo todo, es mejor usar awkotra forma estándar/portátil de hacerlo (tenga en cuenta que awkusa expresiones regulares extendidas):

if STRING=$1 RE='^-[0-9]+$' awk '
  BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'; then
...

O usar una función:

re_match() {
  STRING=$1 RE=$2 awk '
    BEGIN{exit(ENVIRON["STRING"] !~ ENVIRON["RE"])}'
}

if re_match "$1" '^-[0-9]+$'

En este caso, también puedes lograrlo con una caseconstrucción estándar:

case $1 in
  ("" | *[!0-9-]* | [!-]* | - | ?*-*) ;;
  (*) echo match;;
esac

Para usarlo grep, puede usarlo con la --nullopción (cuando sea compatible, ya que no es una opción estándar) para indicarle que funcione en registros delimitados NUL en lugar de registros delimitados por nueva línea. Dado que en la mayoría de los shells $1no puede contener NUL, eso debería ser seguro:

 if printf %s "$1" | grep --null -xq '-[0-9]+$'; then
   echo match
 fi

Respuesta2

Las comillas simples le dicen al shell que mantenga los caracteres adjuntos como están,sin ninguna interpretación. La cadena entre comillas se pasa tal cual a grep, sin las comillas: cuando grepbusca sus argumentos, ve

grep

y

^-[0-9][0-9]*$

y actúa en consecuencia. (LeerCómo se ejecutan los programassi tiene curiosidad acerca de la construcción de argumentos en Linux).

bashy grepson diferentes. La forma en que este comando usa comillas garantiza que bashno procese la cadena, pero greplo hace.

Respuesta3

Las comillas simples previenenglobo(permitiendo bashinterpretar comodines como *) y expansión de variables mediante el uso de $. Básicamente, estás diciendo bash"tomar literalmente esos caracteres y pasárselos a grep". Cuando greplos ve, está diseñado para comprender las expresiones regulares, por lo queentoncesla expresión regular se interpreta dentro grep.

Versión más corta: los argumentos entre comillas simples proporcionan un medio para escapar del procesamiento desde su shell antes de que el argumento se pase al comando.

Respuesta4

Pierde su significado. greputiliza casi los mismos patrones de expresiones regulares que bash.

información relacionada