Me gustaría eliminar el último carácter de una cadena, probé este pequeño script:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
pero imprime "lkj", ¿qué estoy haciendo mal?
Me gustaría eliminar el último carácter de una cadena, probé este pequeño script:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
pero imprime "lkj", ¿qué estoy haciendo mal?
Respuestas:
En un shell POSIX, la sintaxis ${t:-2}
significa algo diferente: se expande al valor de t
si t
está establecido y no es nulo, y de lo contrario al valor 2
. Para recortar un solo carácter por expansión de parámetros, la sintaxis que probablemente desee es${t%?}
Tenga en cuenta que en ksh93
, bash
o zsh
, ${t:(-2)}
o ${t: -2}
(tenga en cuenta el espacio) son legales como una expansión de subcadena, pero probablemente no sean lo que desea, ya que devuelven la subcadena que comienza en una posición a 2 caracteres del final (es decir, elimina el primer carácter i
de la cadena). cadena ijk
).
Consulte la sección de Expansión de parámetros de Shell del Manual de referencia de Bash para obtener más información:
${parameter%word}
elimina el menor coincidencia de patrones sufijo word
- ver la sección de expansión de parámetros deman bash
Con bash
4.2 y superior, puedes hacer:
${var::-1}
Ejemplo:
$ a=123
$ echo "${a::-1}"
12
Tenga en cuenta que para versiones anteriores bash
(por ejemplo, bash 3.2.5
en OS X), debe dejar espacios entre y después de los dos puntos:
${var: : -1}
bash
versión 4.2-alpha y superior, lástima que la versión a la que tengo acceso sea anterior. : - /
${var:offset:lenght}
se agregó solo en bash 4.2
. Quizás OSX agregue su propio parche para bash
.
para eliminar los últimos n
caracteres de una línea que no utiliza sed
OR awk
:
> echo lkj | rev | cut -c (n+1)- | rev
así, por ejemplo, puede eliminar el último carácter one character
usando esto:
> echo lkj | rev | cut -c 2- | rev
> lk
de la página de rev
manual:
DESCRIPCIÓN
La utilidad rev copia los archivos especificados en la salida estándar, invirtiendo el orden de los caracteres en cada línea. Si no se especifican archivos, se lee la entrada estándar.
ACTUALIZAR:
Si no conoce la longitud de la cadena, intente:
$ x="lkj"
$ echo "${x%?}"
lk
Usar sed debería ser tan rápido como
sed 's/.$//'
Tu único eco es entonces echo ljk | sed 's/.$//'
.
Con esto, la cadena de 1 línea podría ser de cualquier tamaño.
Algunas opciones dependiendo del shell:
t=${t%?}
t=`expr " $t" : ' \(.*\).'`
t=${t[1,-2]}
t=${t:0:-1}
t=${t:0:${#t}-1}
t=${t/%?}
t=${t/~(E).$/}
@ {t=$1} ~~ $t *?
Tenga en cuenta que si bien se supone que todos eliminan el último carácter , encontrará que algunas implementaciones (aquellas que no admiten caracteres de varios bytes) eliminan el último byte (por lo que probablemente corrompería el último carácter si fuera de varios bytes) )
La expr
variante supone $t
que no termina en más de un personaje de nueva línea. También devolverá un estado de salida distinto de cero si la cadena resultante termina siendo 0
( 000
o incluso -0
con algunas implementaciones). También podría dar resultados inesperados si la cadena contiene caracteres no válidos.
t=${t%?}
no es Bourne, pero no es probable que encuentres un shell Bourne hoy en día. ${t%?}
funciona en todos los demás sin embargo.
fish
es trabajo en progreso. 2.3.0, que introdujo el string
builtin no se lanzó en el momento de las preguntas y respuestas. Con la versión en la que lo estoy probando, necesita string replace -r '(?s).\z' '' -- $t
(y esperaría que quisieran cambiar eso, deberían cambiar las banderas que pasan a PCRE) o más complicadas. También trata mal con los personajes de nueva línea, y sé que también están planeando cambiar eso.
La respuesta más portátil y más corta es casi seguro:
${t%?}
Esto funciona en bash, sh, ash, dash, busybox / ash, zsh, ksh, etc.
Funciona utilizando la expansión de parámetros de shell de la vieja escuela. Específicamente, %
especifica que se elimine el sufijo de parámetro de coincidencia más pequeño t
que coincida con el patrón global ?
(es decir, cualquier carácter).
Consulte "Eliminar el patrón de sufijo más pequeño" aquí para obtener una explicación (mucho) más detallada y más antecedentes. Consulte también los documentos de su shell (por ejemplo:) man bash
en "expansión de parámetros".
Como nota al margen, si en su lugar desea eliminar el primer carácter, lo usaría ${t#?}
, ya que las #
coincidencias desde el frente de la cadena (prefijo) en lugar de la parte posterior (sufijo).
También vale la pena señalar que ambos %
y #
have %%
y ##
versiones, que coinciden con la versión más larga del patrón dado en lugar de la más corta. Tanto ${t%%?}
y ${t##?}
haría lo mismo como su único operador en este caso, sin embargo (así que no añadir el carácter adicional inútil). Esto se debe a que el ?
patrón dado solo coincide con un solo carácter. Mezclar *
con algunos no comodines y las cosas se vuelven más interesantes con %%
y ##
.
Comprender las expansiones de parámetros, o al menos conocer su existencia y saber cómo buscarlos, es increíblemente útil para escribir y descifrar scripts de shell de muchos sabores. Las expansiones de parámetros a menudo parecen vudú de caparazón arcano para muchas personas porque ... bueno ... son vudú de caparazón arcano (aunque bastante bien documentado si sabe buscar "expansión de parámetro"). Sin embargo, definitivamente es bueno tenerlo en el cinturón de herramientas cuando estás atrapado en un caparazón.
t=lkj
echo ${t:0:${#t}-1}
Obtiene una subcadena de 0 a la longitud de la cadena -1. Sin embargo, tenga en cuenta que esta resta es específica de bash y no funcionará en otros shells.
Por ejemplo, dash
no puede analizar incluso
echo ${t:0:$(expr ${#t} - 1)}
Por ejemplo, en Ubuntu, /bin/sh
esdash
También puede usar head
para imprimir todo menos el último carácter.
$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin
Pero desafortunadamente algunas versiones de head
no incluyen la -
opción principal . Este es el caso de lo head
que viene con OS X.
Solo para completar algunos usos posibles de bash puro:
#!/bin/bash
# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"
La primera sintaxis toma una subcadena de una cadena, la sintaxis es
Para la segunda, observe el signo, que significa 'desde el final de la línea' y la sintaxis es
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}
Y aquí hay dos formas más cortas de lo mencionado anteriormente
echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"
Aquí observe nuevamente el %
signo, que significa 'Eliminar (es decir, reemplazar con' ') el patrón coincidente más corto (aquí representado por el espacio escapado ' \ ' desde el final del PARÁMETRO , aquí llamado STR