string - reemplazar - scripts bash ejemplos
¿Cómo recortar espacios en blanco de una variable Bash? (30)
Pele un espacio delantero y uno trasero
trim()
{
local trimmed="$1"
# Strip leading space.
trimmed="${trimmed## }"
# Strip trailing space.
trimmed="${trimmed%% }"
echo "$trimmed"
}
Por ejemplo:
test1="$(trim " one leading")"
test2="$(trim "one trailing ")"
test3="$(trim " one leading and one trailing ")"
echo "''$test1'', ''$test2'', ''$test3''"
Salida:
''one leading'', ''one trailing'', ''one leading and one trailing''
Pele todos los espacios iniciales y finales
trim()
{
local trimmed="$1"
# Strip leading spaces.
while [[ $trimmed == '' ''* ]]; do
trimmed="${trimmed## }"
done
# Strip trailing spaces.
while [[ $trimmed == *'' '' ]]; do
trimmed="${trimmed%% }"
done
echo "$trimmed"
}
Por ejemplo:
test4="$(trim " two leading")"
test5="$(trim "two trailing ")"
test6="$(trim " two leading and two trailing ")"
echo "''$test4'', ''$test5'', ''$test6''"
Salida:
''two leading'', ''two trailing'', ''two leading and two trailing''
Tengo un script de shell con este código:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Pero el código condicional siempre se ejecuta, porque hg st
siempre imprime al menos un carácter de nueva línea.
- ¿Existe una forma sencilla de eliminar los espacios en blanco de
$var
(comotrim()
en PHP )?
o
- ¿Hay una manera estándar de tratar este problema?
Podría usar sed o AWK , pero me gustaría pensar que hay una solución más elegante para este problema.
Aquí hay una función trim () que recorta y normaliza los espacios en blanco
#!/bin/bash
function trim {
echo $*
}
echo "''$(trim " one two three ")''"
# ''one two three''
Y otra variante que utiliza expresiones regulares.
#!/bin/bash
function trim {
local trimmed="$@"
if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]
then
trimmed=${BASH_REMATCH[1]}
fi
echo "$trimmed"
}
echo "''$(trim " one two three ")''"
# ''one two three''
Bash tiene una característica llamada expansión de parámetros , que, entre otras cosas, permite el reemplazo de cadenas basadas en los llamados patrones (los patrones se asemejan a las expresiones regulares, pero existen diferencias y limitaciones fundamentales). [línea original de flussence: Bash tiene expresiones regulares, pero están bien ocultas:]
A continuación se muestra cómo eliminar todos los espacios en blanco (incluso desde el interior) de un valor variable.
$ var=''abc def''
$ echo "$var"
abc def
# Note: flussence''s original expression was "${var/ /}", which only replaced the *first* space char., wherever it appeared.
$ echo -n "${var//[[:space:]]/}"
abcdef
Con las funciones de coincidencia de patrones extendidas de Bash habilitadas ( shopt -s extglob
), puedes usar esto:
{trimmed##*( )}
para eliminar una cantidad arbitraria de espacios iniciales.
De la sección de Bash Guide en globbing
Para usar un extglob en una expansión de parámetros
#Turn on extended globbing
shopt -s extglob
#Trim leading and trailing whitespace from a variable
x=${x##+([[:space:]])}; x=${x%%+([[:space:]])}
#Turn off extended globbing
shopt -u extglob
Aquí está la misma funcionalidad envuelta en una función (NOTA: es necesario citar la cadena de entrada pasada a la función):
trim() {
# Determine if ''extglob'' is currently on.
local extglobWasOff=1
shopt extglob >/dev/null && extglobWasOff=0
(( extglobWasOff )) && shopt -s extglob # Turn ''extglob'' on, if currently turned off.
# Trim leading and trailing whitespace
local var=$1
var=${var##+([[:space:]])}
var=${var%%+([[:space:]])}
(( extglobWasOff )) && shopt -u extglob # If ''extglob'' was off before, turn it back off.
echo -n "$var" # Output trimmed string.
}
Uso:
string=" abc def ghi ";
#need to quote input-string to preserve internal white-space if any
trimmed=$(trim "$string");
echo "$trimmed";
Si modificamos la función para que se ejecute en una subshell, no tenemos que preocuparnos por examinar la opción de shell actual para extglob, podemos configurarlo sin afectar al shell actual. Esto simplifica enormemente la función. También actualizo los parámetros posicionales "en su lugar", por lo que ni siquiera necesito una variable local
trim() (
shopt -s extglob
set -- "${1##+([[:space:]])}"
printf "%s" "${1%%+([[:space:]])}"
)
asi que:
$ s=$''/t/n /r/tfoo ''
$ shopt -u extglob
$ shopt extglob
extglob off
$ printf ">%q</n" "$s" "$(trim "$s")"
>$''/t/n /r/tfoo ''<
>foo<
$ shopt extglob
extglob off
Definamos una variable que contenga espacios en blanco iniciales, finales y intermedios:
FOO='' test test test ''
echo -e "FOO=''${FOO}''"
# > FOO='' test test test ''
echo -e "length(FOO)==${#FOO}"
# > length(FOO)==16
Cómo eliminar todo el espacio en blanco (indicado por [:space:]
en tr
):
FOO='' test test test ''
FOO_NO_WHITESPACE="$(echo -e "${FOO}" | tr -d ''[:space:]'')"
echo -e "FOO_NO_WHITESPACE=''${FOO_NO_WHITESPACE}''"
# > FOO_NO_WHITESPACE=''testtesttest''
echo -e "length(FOO_NO_WHITESPACE)==${#FOO_NO_WHITESPACE}"
# > length(FOO_NO_WHITESPACE)==12
Cómo eliminar solo los espacios en blanco iniciales:
FOO='' test test test ''
FOO_NO_LEAD_SPACE="$(echo -e "${FOO}" | sed -e ''s/^[[:space:]]*//'')"
echo -e "FOO_NO_LEAD_SPACE=''${FOO_NO_LEAD_SPACE}''"
# > FOO_NO_LEAD_SPACE=''test test test ''
echo -e "length(FOO_NO_LEAD_SPACE)==${#FOO_NO_LEAD_SPACE}"
# > length(FOO_NO_LEAD_SPACE)==15
Cómo eliminar solo los espacios en blanco finales:
FOO='' test test test ''
FOO_NO_TRAIL_SPACE="$(echo -e "${FOO}" | sed -e ''s/[[:space:]]*$//'')"
echo -e "FOO_NO_TRAIL_SPACE=''${FOO_NO_TRAIL_SPACE}''"
# > FOO_NO_TRAIL_SPACE='' test test test''
echo -e "length(FOO_NO_TRAIL_SPACE)==${#FOO_NO_TRAIL_SPACE}"
# > length(FOO_NO_TRAIL_SPACE)==15
Cómo eliminar los espacios iniciales y finales: encadene los sed
s:
FOO='' test test test ''
FOO_NO_EXTERNAL_SPACE="$(echo -e "${FOO}" | sed -e ''s/^[[:space:]]*//'' -e ''s/[[:space:]]*$//'')"
echo -e "FOO_NO_EXTERNAL_SPACE=''${FOO_NO_EXTERNAL_SPACE}''"
# > FOO_NO_EXTERNAL_SPACE=''test test test''
echo -e "length(FOO_NO_EXTERNAL_SPACE)==${#FOO_NO_EXTERNAL_SPACE}"
# > length(FOO_NO_EXTERNAL_SPACE)==14
Alternativamente, si su bash lo admite, puede reemplazar echo -e "${FOO}" | sed ...
echo -e "${FOO}" | sed ...
con sed ... <<<${FOO}
, así (para espacios en blanco al final):
FOO_NO_TRAIL_SPACE="$(sed -e ''s/[[:space:]]*$//'' <<<${FOO})"
Esto funcionó para mí:
text=" trim my edges "
trimmed=$text
trimmed=${trimmed##+( )} #Remove longest matching series of spaces from the front
trimmed=${trimmed%%+( )} #Remove longest matching series of spaces from the back
echo "<$trimmed>" #Adding angle braces just to make it easier to confirm that all spaces are removed
#Result
<trim my edges>
Para poner eso en menos líneas para el mismo resultado:
text=" trim my edges "
trimmed=${${text##+( )}%%+( )}
Esto no tiene el problema con los globos no deseados, además, los espacios en blanco interiores no están modificados (asumiendo que $IFS
está establecido en el valor predeterminado, que es '' /t/n''
).
Se lee hasta la primera nueva línea (y no la incluye) o el final de la cadena, lo que ocurra primero, y elimina cualquier combinación de espacio y /t
caracteres iniciales y finales . Si desea conservar varias líneas (y también quitar nuevas líneas iniciales y finales), use read -r -d '''' var << eof
en su lugar; tenga en cuenta, sin embargo, que si su entrada contiene /neof
, se cortará justo antes. (Otras formas de espacio en blanco, a saber /r
, /f
y /v
, no se eliminan, incluso si se agregan a $ IFS).
read -r var << eof
$var
eof
Hay muchas respuestas, pero sigo creyendo que vale la pena mencionar mi guión recién escrito porque:
- fue probado exitosamente en el shell bash / dash / busybox shell
- es extremadamente pequeño
- no depende de comandos externos y no necesita bifurcar (-> uso de recursos rápido y bajo)
- funciona como se esperaba
- elimina todos los espacios y tabulaciones de principio a fin, pero no más
- importante: no elimina nada del medio de la cadena (muchas otras respuestas lo hacen), incluso las nuevas líneas permanecerán
- especial: el
"$*"
une varios argumentos usando un espacio. Si desea recortar y generar solo el primer argumento, use"$1"
lugar - Si no tiene ningún problema con los patrones de nombre de archivo coincidentes, etc.
La secuencia de comandos:
trim() {
local s2 s="$*"
# note: the brackets in each of the following two lines contain one space
# and one tab
until s2="${s#[ ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
until s2="${s%[ ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
echo "$s"
}
Uso:
mystring=" here is
something "
mystring=$(trim "$mystring")
echo ">$mystring<"
Salida:
>here is
something<
Hay una solución que solo usa Bash incorporados llamados comodines :
var=" abc "
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo "===$var==="
Aquí está el mismo envuelto en una función:
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
Pasas la cadena para ser recortada en forma de cita. p.ej:
trim " abc "
Lo bueno de esta solución es que funcionará con cualquier shell compatible con POSIX.
Referencia
He visto que los scripts solo usan la asignación de variables para hacer el trabajo:
$ xyz=`echo -e ''foo /n bar''`
$ echo $xyz
foo bar
El espacio en blanco se fusiona y recorta automáticamente. Hay que tener cuidado con los metacaracteres de la cáscara (riesgo de inyección potencial).
También recomendaría siempre las citas de doble sustitución de variables en condicionales de shell:
if [ -n "$var" ]; then
ya que algo como un -o u otro contenido en la variable podría modificar sus argumentos de prueba.
Para eliminar todos los espacios desde el principio y el final de una cadena (incluidos los caracteres de final de línea):
echo $variable | xargs echo -n
Esto eliminará espacios duplicados también:
echo " this string has a lot of spaces " | xargs echo -n
Produce: ''esta cadena tiene muchos espacios''
Puedes eliminar nuevas líneas con tr
:
var=`hg st -R "$path" | tr -d ''/n''`
if [ -n $var ]; then
echo $var
done
Puedes recortar simplemente con echo
:
foo=" qsdqsd qsdqs q qs "
# Not trimmed
echo /'$foo/'
# Trim
foo=`echo $foo`
# Trimmed
echo /'$foo/'
Puedes usar la vieja escuela tr
. Por ejemplo, esto devuelve el número de archivos modificados en un repositorio de git, espacios en blanco eliminados.
MYVAR=`git ls-files -m|wc -l|tr -d '' ''`
Siempre lo he hecho con sed
var=`hg st -R "$path" | sed -e ''s/ *$//''`
Si hay una solución más elegante, espero que alguien la publique.
Simplemente usaría sed:
function trim
{
echo "$1" | sed -n ''1h;1!H;${;g;s/^[ /t]*//g;s/[ /t]*$//g;p;}''
}
a) Ejemplo de uso en cadena de una sola línea
string='' wordA wordB wordC wordD ''
trimmed=$( trim "$string" )
echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"
Salida:
GIVEN STRING: | wordA wordB wordC wordD |
TRIMMED STRING: |wordA wordB wordC wordD|
b) Ejemplo de uso en cadena multilínea
string='' wordA
>wordB<
wordC ''
trimmed=$( trim "$string" )
echo -e "GIVEN STRING: |$string|/n"
echo "TRIMMED STRING: |$trimmed|"
Salida:
GIVEN STRING: | wordAA
>wordB<
wordC |
TRIMMED STRING: |wordAA
>wordB<
wordC|
c) Nota final:
Si no te gusta usar una función, para una cadena de una sola línea simplemente puedes usar un comando "más fácil de recordar" como:
echo "$string" | sed -e ''s/^[ /t]*//'' | sed -e ''s/[ /t]*$//''
Ejemplo:
echo " wordA wordB wordC " | sed -e ''s/^[ /t]*//'' | sed -e ''s/[ /t]*$//''
Salida:
wordA wordB wordC
El uso de lo anterior en cadenas de varias líneas también funcionará , pero tenga en cuenta que también reducirá cualquier espacio interno múltiple final / posterior, como GuruM observó en los comentarios
string='' wordAA
>four spaces before<
>one space before< ''
echo "$string" | sed -e ''s/^[ /t]*//'' | sed -e ''s/[ /t]*$//''
Salida:
wordAA
>four spaces before<
>one space before<
Entonces, si te importa mantener esos espacios, ¡usa la función al principio de mi respuesta!
d) EXPLICACIÓN de la sintaxis sed "buscar y reemplazar" en cadenas de varias líneas utilizadas dentro del ajuste de función:
sed -n ''
# If the first line, copy the pattern to the hold buffer
1h
# If not the first line, then append the pattern to the hold buffer
1!H
# If the last line then ...
$ {
# Copy from the hold to the pattern buffer
g
# Do the search and replace
s/^[ /t]*//g
s/[ /t]*$//g
# print
p
}''
Una respuesta simple es:
echo " lol " | xargs
Xargs hará el recorte por ti. Es un comando / programa, sin parámetros, devuelve la cadena recortada, ¡así de fácil!
Nota: esto no elimina los espacios internos, por lo que "foo bar"
permanece igual. NO se convierte en "foobar"
.
Esto eliminará todos los espacios en blanco de su cadena,
VAR2="${VAR2//[[:space:]]/}"
/
reemplaza la primera aparición y //
todas las apariciones de espacios en blanco en la cadena. Es decir, todos los espacios en blanco son reemplazados por - nada
Esto recorta múltiples espacios de la parte delantera y final.
whatever=${whatever%% *}
whatever=${whatever#* }
Las asignaciones ignoran los espacios en blanco iniciales y finales y, como tales, se pueden usar para recortar:
$ var=`echo '' hello''`; echo $var
hello
Para eliminar espacios y tabulaciones de la izquierda a la primera palabra, ingrese:
echo " This is a test" | sed "s/^[ /t]*//"
cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html
Utilice AWK:
echo $var | awk ''{gsub(/^ +| +$/,"")}1''
Descubrí que necesitaba agregar algo de código de una sdiff
salida desordenada para limpiarlo:
sdiff -s column1.txt column2.txt | grep -F ''<'' | cut -f1 -d"<" > c12diff.txt
sed -n 1''p'' c12diff.txt | sed ''s/ *$//g'' | tr -d ''/n'' | tr -d ''/t''
Esto elimina los espacios finales y otros caracteres invisibles.
Este es el método más simple que he visto. Solo usa Bash, solo unas pocas líneas, la expresión regular es simple y coincide con todas las formas de espacio en blanco:
if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then
test=${BASH_REMATCH[1]}
fi
Aquí hay un script de ejemplo para probarlo con:
test=$(echo -e "/n /t Spaces and tabs and newlines be gone! /t /n ")
echo "Let''s see if this works:"
echo
echo "----------"
echo -e "Testing:${test} :Tested" # Ugh!
echo "----------"
echo
echo "Ugh! Let''s fix that..."
if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then
test=${BASH_REMATCH[1]}
fi
echo
echo "----------"
echo -e "Testing:${test}:Tested" # "Testing:Spaces and tabs and newlines be gone!"
echo "----------"
echo
echo "Ah, much better."
Python tiene una función strip()
que funciona de manera idéntica a la de PHP trim()
, así que solo podemos hacer un poco de Python en línea para hacer una utilidad fácilmente comprensible para esto:
alias trim=''python -c "import sys; sys.stdout.write(sys.stdin.read().strip())"''
Esto recortará los espacios en blanco iniciales y finales (incluidas las nuevas líneas).
$ x=`echo -e "/n/t /n" | trim`
$ if [ -z "$x" ]; then echo hi; fi
hi
# Strip leading and trailing white space (new line inclusive).
trim(){
[[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
printf "%s" "$BASH_REMATCH"
}
O
# Strip leading white space (new line inclusive).
ltrim(){
[[ "$1" =~ [^[:space:]].* ]]
printf "%s" "$BASH_REMATCH"
}
# Strip trailing white space (new line inclusive).
rtrim(){
[[ "$1" =~ .*[^[:space:]] ]]
printf "%s" "$BASH_REMATCH"
}
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "$(rtrim "$(ltrim "$1")")"
}
O
# Strip leading and trailing specified characters. ex: str=$(trim "$str" $''/n a'')
trim(){
if [ "$2" ]; then
trim_chrs="$2"
else
trim_chrs="[:space:]"
fi
[[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
printf "%s" "${BASH_REMATCH[1]}"
}
O
# Strip leading specified characters. ex: str=$(ltrim "$str" $''/n a'')
ltrim(){
if [ "$2" ]; then
trim_chrs="$2"
else
trim_chrs="[:space:]"
fi
[[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]]
printf "%s" "${BASH_REMATCH[1]}"
}
# Strip trailing specified characters. ex: str=$(rtrim "$str" $''/n a'')
rtrim(){
if [ "$2" ]; then
trim_chrs="$2"
else
trim_chrs="[:space:]"
fi
[[ "$1" =~ ^(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
printf "%s" "${BASH_REMATCH[1]}"
}
# Strip leading and trailing specified characters. ex: str=$(trim "$str" $''/n a'')
trim(){
printf "%s" "$(rtrim "$(ltrim "$1" "$2")" "$2")"
}
O
Sobre la base de la exputación de Moskit ...
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "`expr "$1" : "^[[:space:]]*/(.*[^[:space:]]/)[[:space:]]*$"`"
}
O
# Strip leading white space (new line inclusive).
ltrim(){
printf "%s" "`expr "$1" : "^[[:space:]]*/(.*[^[:space:]]/)"`"
}
# Strip trailing white space (new line inclusive).
rtrim(){
printf "%s" "`expr "$1" : "^/(.*[^[:space:]]/)[[:space:]]*$"`"
}
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "$(rtrim "$(ltrim "$1")")"
}
# Trim whitespace from both ends of specified parameter
trim () {
read -rd '''' $1 <<<"${!1}"
}
# Unit test for trim()
test_trim () {
local foo="$1"
trim foo
test "$foo" = "$2"
}
test_trim hey hey &&
test_trim '' hey'' hey &&
test_trim ''ho '' ho &&
test_trim ''hey ho'' ''hey ho'' &&
test_trim '' hey ho '' ''hey ho'' &&
test_trim $''/n/n/t hey/n/t ho /t/n'' $''hey/n/t ho'' &&
test_trim $''/n'' '''' &&
test_trim ''/n'' ''/n'' &&
echo passed
#!/bin/bash
function trim
{
typeset trimVar
eval trimVar="/${$1}"
read trimVar << EOTtrim
$trimVar
EOTtrim
eval $1=/$trimVar
}
# Note that the parameter to the function is the NAME of the variable to trim,
# not the variable contents. However, the contents are trimmed.
# Example of use:
while read aLine
do
trim aline
echo "[${aline}]"
done < info.txt
# File info.txt contents:
# ------------------------------
# ok hello there $
# another line here $
#and yet another $
# only at the front$
#$
# Output:
#[ok hello there]
#[another line here]
#[and yet another]
#[only at the front]
#[]
var='' a b c ''
trimmed=$(echo $var)