Linux Fu: Cadenas Bash
Si eres un programador tradicional, usando bash
porque un script puede parecer restrictivo a veces, pero para ciertas tareas, bash
puede ser muy productivo. Resulta que algunos de los límites de bash
realmente hay límites de shells más antiguos y código de personas para que sean compatibles. Otros problemas percibidos se deben a algunas de las características avanzadas en bash
son arcanos o confusos.
Las cuerdas son un buen ejemplo. no piensas en bash
como un lenguaje de manejo de cadenas, pero tiene muchas formas poderosas de manejar cadenas. De hecho, puede tener demasiadas formas, porque la funcionalidad termina en más de un lugar. Por supuesto, también puede llamar a los programas y, a veces, es más fácil llamar awk
o un script de Python para hacer la carga pesada.
Pero quedémonos con bash
-ismos para manejar cadenas. Obviamente, puede colocar una cadena en una variable de entorno y retirarla. Supongo que sabes cómo funcionan la interpolación y las comillas de cadenas. En otras palabras, esto debería tener sentido:
echo "Your path is $PATH and the current directory is ${PWD}"
El largo y el corto
Supongamos que desea saber la longitud de una cadena. Esta es una operación de cadena bastante básica. En bash
puedes escribir ${#var}
encontrar la longitud de $var
:
#/bin/bash echo -n "Project Name? " read PNAME if (( ${#PNAME} > 16 )) then echo Error: Project name longer than 16 characters else echo ${PNAME} it is! fi
El "(" forma un contexto aritmético, por lo que puede salirse con la suya con un mayor que un signo tácito aquí. Si no le importa usar expr
- que es un programa externo - hay al menos dos formas adicionales de llegar allí:
echo ${#STR} expr length "${STR}" expr match "${STR}" '.*'
Por supuesto, si te permites llamar fuera de bash
podrías usar awk
o algo más para hacer esto también, pero nos quedaremos expr
porque es relativamente ligero.
Cuchillo del ejército suizo
De hecho, expr
puede hacer muchas manipulaciones de cadenas además de la longitud y la compatibilidad. Puedes tirar de una cuerda de una cuerda usando substr
. A menudo es conveniente usar index
primero busque un carácter separado en la cadena. La expr
El programa usa 1 como el primer carácter de la cadena. Así por ejemplo:
#/bin/bash echo -n "Full path? " read FFN LAST_SLASH=0 SLASH=$( expr index "$FFN" / ) # find first slash while (( $SLASH != 0 )) do let LAST_SLASH=$LAST_SLASH+$SLASH # point at next slash SLASH=$(expr index "${FFN:$LAST_SLASH}" / ) # look for another done # now LAST_SLASH points to last slash echo -n "Directory: " expr substr "$FFN" 1 $LAST_SLASH echo -or- echo ${FFN:0:$LAST_SLASH} # Yes, I know about dirname but this is an example
Introduzca la ruta completa (como /foo/bar/la-tecnologia
) y el script encontrará la última barra inclinada e imprimirá el nombre hasta la última barra inclinada inclusive usando dos métodos diferentes. Este guión se utiliza expr
pero también usa la sintaxis para bash
'es una extracción de subcadena incorporada que comienza en el índice cero. Por ejemplo, si la variable FOO contiene "La-Tecnologia":
- $ {FOO} -> La-Tecnologia
- $ {FOO: 1} -> día de pago
- $ {FOO: 5: 3} -> día
- $ {FOO: -3} -> día
- $ {FOO: 1: -4} -> acuse de recibo
- $ {FOO: -8: -4} -> Hackear
El primer número se compensa y el segundo es la longitud si es positivo. También puede hacer que cualquiera de los números sea negativo, aunque necesita un espacio después de los dos puntos si el desplazamiento es negativo. El último carácter de la cadena está en el índice -1, por ejemplo. La longitud negativa es una forma abreviada de una posición absoluta del final de la cadena. Hacer:
Por supuesto, cualquiera de los dos números podría ser variable, como puede ver en el ejemplo.
Menos es más
A veces no quieres encontrar algo, solo quieres deshacerte de él. bash
tiene muchas formas de eliminar subcadenas con cadenas fijas o coincidencia de patrones basados en globo. Hay cuatro variaciones. Un par de eliminaciones elimina las subcadenas más largas y más cortas posibles del frente de la cadena y el otro par hace lo mismo desde la parte posterior de la cadena. Considera esto:
TSTR=my.first.file.txt echo ${TSTR%.*} # prints my.first.file echo ${TSTR%%.*} # prints my echo ${TSTR#*fi} # prints rst.file.txt echo $TSTR##*fi} # prints le.txt
Transformación
Por supuesto, a veces no desea eliminar tanto como desea reemplazar una cadena con otra cadena. Puede usar una sola barra para reemplazar la primera aparición de una cadena de búsqueda o dos barras para reemplazar en todo el mundo. También es posible que no proporcione un cable de reemplazo y se le dará otra forma de quitar partes del cable. Otro truco es agregar # o% para anclar la coincidencia al principio o al final de la cadena, como con la eliminación.
TSTR=my.first.file.txt echo ${TSTR/fi/Fi} # my.First.file.txt echo ${TSTR//fi/Fi} # my.First.File.txt echo ${TSTR/#*./PREFIX-} # PREFIX-txt (note: always longest match) echo ${TSTR/%.*/.backup} # my.backup (note: always longest match)
Varios
Algunas de las formas más comunes de manejar cuerdas bash
se refiere al tratamiento de los parámetros. Suponga que tiene un script esperando una variable llamada OTERM
para ser configurado pero quiere estar seguro:
REALTERM=${OTERM:-vt100}
Ahora REALTERM
tendrá el valor de OTERM
o la cadena "vt100" si no hubiera nada en ella OTERM
. A veces quieres configurar OTERM
en sí mismo, por lo que si bien podría asignar a OTERM
en lugar de REALTERM
, Hay una manera más fácil. Use: = en lugar de: - secuencia. Si hace esto, no necesita ninguna tarea, aunque puede usar una si lo desea:
echo ${OTERM:=vt100} # now OTERM is vt100 if it was empty before
También puede invertir el significado para reemplazar el valor solo si el valor principal no está vacío, aunque esto generalmente no es tan útil:
echo ${DEBUG:+"Debug mode is ON"} # reverse -; no assignment
Una medida más drástica le permite imprimir un mensaje de error en stderr y detener un shell no interactivo:
REALTERM=${OTERM:?"Error. Please set OTERM before calling this script"}
De todos modos
Convertir mayúsculas o minúsculas es bastante sencillo. Puede proporcionar un patrón de globo que coincida con un solo carácter. Si lo omite, es lo mismo que ?, que coincide con cualquier carácter. Puede optar por cambiar todos los caracteres coincidentes o simplemente intentar hacer coincidir el primer carácter. Aquí están los ejemplos requeridos:
NAME="joe La-Tecnologia" echo ${NAME^} # prints Joe La-Tecnologia (first match of any character) echo ${NAME^^} # prints JOE la-tecnologia.com (all of any character) echo ${NAME^^[a]} # prints joe la-tecnologia.com (all a characters) echo ${NAME,,] # prints joe la-tecnologia (all characters) echo ${NAME,] # prints joe La-Tecnologia (first character matched and didn't convert) NAME="Joe La-Tecnologia" echo ${NAME,,[A-H]} # prints Joe la-tecnologia (apply pattern to all characters and convert A-H to lowercase)
Últimas versiones de bash
también puede convertir mayúsculas y minúsculas usando ${[email protected]}
y ${[email protected]}
junto con solo el primer carácter usando @u
y @l
pero tu kilometraje puede variar.
Aprobar el examen
Probablemente haya notado que cuando realiza una prueba estándar, en realidad se llama programa:
if [ $f -eq 0 ] then ...
Si haces ls en /usr/bin
verás lo que en realidad se puede llamar "[” used as a shorthand for the test program. However, bash
has its own test in the form of two brackets:
if [[ $f == 0 ] entonces ...
Esta prueba integrada puede manejar expresiones regulares usando = ~, por lo que esta es otra opción para hacer coincidir cadenas:
if [[ "$NAME" =~ [hH]a.k ]] ...
Elegir sabiamente
Por supuesto, si procesa mucho texto, es posible que no necesite usarlo bash
. Incluso si lo eres, no olvides que siempre puedes usar otros programas como tr, awk
, sed
, y muchos otros para hacer tales cosas. Claro, actuar no será tan bueno, probablemente, pero si te importa actuar, ¿por qué escribir un guión?
A menos que estés maldiciendo por completo un guión, es bueno tener algunos de estos trucos en tu bolsillo trasero. Úselos sabiamente.