scripts script reemplazar operaciones ejemplos comparar caracteres caracter cadenas cadena buscar aritmeticas string bash variables trim

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 (como trim() 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 /tcaracteres iniciales y finales . Si desea conservar varias líneas (y también quitar nuevas líneas iniciales y finales), use read -r -d '''' var << eofen 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, /fy /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



Utilice AWK:

echo $var | awk ''{gsub(/^ +| +$/,"")}1''


Descubrí que necesitaba agregar algo de código de una sdiffsalida 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)