Comment couper des espaces blancs à partir d'une variable Bash?

j'ai un script shell avec ce code:

var=`hg st -R "$path"`
if [ -n "$var" ]; then
    echo $var
fi

mais le code conditionnel s'exécute toujours, car hg st imprime toujours au moins un caractère newline.

  • Existe-t-il un moyen simple de supprimer les espaces de $var (comme trim() dans PHP )?

ou

  • Existe-t-il une façon standard de traiter cette question?

je pourrais utiliser sed ou AWK , mais j'aimerais penser qu'il existe une solution plus élégante à ce problème.

679
demandé sur too much php 2008-12-16 00:24:01

30 réponses

définissons une variable contenant l'espace principal, l'espace secondaire et l'espace intermédiaire:

FOO=' test test test '
echo -e "FOO='${FOO}'"
# > FOO=' test test test '
echo -e "length(FOO)==${#FOO}"
# > length(FOO)==16

Comment supprimer tous les espaces (indiqué par [:space:] dans 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

Comment supprimer les espaces blancs seulement:

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

Comment supprimer les espaces blancs seulement:

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

comment enlever à la fois les espaces avant et arrière--chaîne le 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

alternativement, si votre bash le supporte, Vous pouvez remplacer echo -e "${FOO}" | sed ... par sed ... <<<${FOO} , comme ainsi (pour suivre l'espace):

FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
830
répondu MattyV 2017-06-20 10:14:06

une réponse simple est:

echo "   lol  " | xargs

Xargs fera l'élagage pour vous. C'est une commande/programme, pas de paramètres, renvoie la chaîne ajustée, c'est très simple!

Note: cela ne supprime pas les espaces internes de sorte que "foo bar" reste le même. Il ne devient pas "foobar" .

672
répondu makevoid 2015-09-25 18:56:48

il y a une solution qui n'utilise que les Bash built-ins appelés wildcards :

var="    abc    "
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"   
echo "===$var==="

voici le même enveloppé dans une fonction:

trim() {
    local var="$*"
    # remove leading whitespace characters
    var="${var#"${var%%[![:space:]]*}"}"
    # remove trailing whitespace characters
    var="${var%"${var##*[![:space:]]}"}"   
    echo -n "$var"
}

vous passez la chaîne à couper en forme de citation. par exemple:

trim "   abc   "

une bonne chose au sujet de cette solution est qu'elle fonctionnera avec n'importe quel shell conforme à POSIX.

référence

257
répondu Mateusz Piotrowski 2017-02-23 14:48:34

Bash a une caractéristique appelée expansion de paramètre , qui, entre autres choses, permet le remplacement de chaîne basée sur soi-disant modèles (les modèles ressemblent à des expressions régulières, mais il y a des différences et des limites fondamentales). [flussence original ligne: Bash a des expressions régulières, mais ils sont bien cachés:]

ce qui suit montre comment supprimer tout espace blanc (même de la intérieur) à partir d'une valeur 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
65
répondu 2 revs, 2 users 67%user42092 2012-06-04 15:38:58

vous pouvez couper simplement avec echo :

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'
35
répondu VAmp 2015-09-25 18:58:17

Bande un espace de tête et un espace de fuite

trim()
{
    local trimmed=""

    # Strip leading space.
    trimmed="${trimmed## }"
    # Strip trailing space.
    trimmed="${trimmed%% }"

    echo "$trimmed"
}

par exemple:

test1="$(trim " one leading")"
test2="$(trim "one trailing ")"
test3="$(trim " one leading and one trailing ")"
echo "'$test1', '$test2', '$test3'"

sortie:

'one leading', 'one trailing', 'one leading and one trailing'

Strip tous attaque et de fuite des espaces

trim()
{
    local trimmed=""

    # Strip leading spaces.
    while [[ $trimmed == ' '* ]]; do
       trimmed="${trimmed## }"
    done
    # Strip trailing spaces.
    while [[ $trimmed == *' ' ]]; do
        trimmed="${trimmed%% }"
    done

    echo "$trimmed"
}

par exemple:

test4="$(trim "  two leading")"
test5="$(trim "two trailing  ")"
test6="$(trim "  two leading and two trailing  ")"
echo "'$test4', '$test5', '$test6'"

sortie:

'two leading', 'two trailing', 'two leading and two trailing'
35
répondu wjandrea 2017-12-09 02:08:28

afin de supprimer tous les espaces du début et de la fin d'une chaîne (y compris les caractères de fin de ligne):

echo $variable | xargs echo -n

ceci supprimera les espaces en double aussi:

echo "  this string has a lot       of spaces " | xargs echo -n

Produit: "cette chaîne a beaucoup d'espaces"

30
répondu rkachach 2016-12-04 18:28:09

de la section Guide Bash sur globbing

, Pour utiliser une extglob dans un paramètre d'extension

 #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  

Voici la même fonctionnalité enveloppée dans une fonction (NOTE: besoin de citer chaîne de saisie passée à la fonction):

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=
    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.
}

Utilisation:

string="   abc def ghi  ";
#need to quote input-string to preserve internal white-space if any
trimmed=$(trim "$string");  
echo "$trimmed";

si nous modifions la fonction à exécuter dans un sous-puits, nous n'avons pas à nous soucier en examinant l'option shell actuelle pour extglob, nous pouvons simplement la définir sans affecter le shell actuel. Cela simplifie énormément la fonction. J'ai également mis à jour les paramètres de position "en place" afin que je n'ai même pas besoin d'une variable locale

trim() (
    shopt -s extglob
    set -- "${1##+([[:space:]])}"
    printf "%s" "${1%%+([[:space:]])}" 
)

:

$ 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
26
répondu GuruM 2018-08-29 17:50:16

avec les caractéristiques étendues de correspondance des motifs de Bash activées ( shopt -s extglob ), vous pouvez utiliser ceci:

{trimmed##*( )}

pour supprimer une quantité arbitraire d'espaces de tête.

22
répondu Mooshu 2015-09-25 18:46:08

vous pouvez supprimer les nouvelles lignes avec tr :

var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
    echo $var
done
18
répondu Adam Rosenfield 2008-12-15 21:42:26
# Trim whitespace from both ends of specified parameter

trim () {
    read -rd ''  <<<"${!1}"
}

# Unit test for trim()

test_trim () {
    local foo=""
    trim foo
    test "$foo" = ""
}

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
17
répondu flabdablet 2012-01-25 08:45:42

Je l'ai toujours fait avec sed

  var=`hg st -R "$path" | sed -e 's/  *$//'`

S'il y a une solution plus élégante, j'espère que quelqu'un la poste.

16
répondu Paul Tomblin 2008-12-15 21:28:48

il y a beaucoup de réponses, mais je crois toujours que mon script juste écrit vaut la peine d'être mentionné parce que:

  • il a été testé avec succès dans les shells bash/tableau de bord/busybox shell
  • il est extrêmement petit
  • il ne dépend pas des commandes externes et n'a pas besoin de bifurquer (->utilisation rapide et faible des ressources)
  • ça marche comme prévu:
    • bandes tous les espaces et onglets du début et de la fin, mais pas plus
    • important: il ne supprime rien du milieu de la chaîne (de nombreuses autres réponses le font), même les nouvelles lignes resteront
    • spécial: le "$*" rejoint plusieurs arguments à l'aide d'un espace. si vous voulez couper & sortie seulement le premier argument, utilisez "" à la place
    • si n'a pas de problèmes avec les modèles de nom de fichier, etc

Le script:

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"
}

Utilisation:

mystring="   here     is
    something    "
mystring=$(trim "$mystring")
echo ">$mystring<"

sortie:

>here     is
    something<
10
répondu Daniel Alder 2016-04-23 13:39:04

vous pouvez utiliser old-school tr . Par exemple, cela renvoie le nombre de fichiers modifiés dans un dépôt git, espaces dépouillés.

MYVAR=`git ls-files -m|wc -l|tr -d ' '`
9
répondu pojo 2009-11-27 09:49:36

cela a fonctionné pour moi:

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>

pour mettre cela sur moins de lignes pour le même résultat:

text="    trim my edges    "
trimmed=${${text##+( )}%%+( )}
8
répondu gmale 2015-09-25 19:01:26

j'ai vu des scripts juste utiliser l'assignation de variable pour faire le travail:

$ xyz=`echo -e 'foo \n bar'`
$ echo $xyz
foo bar

espace blanc est automatiquement coalesced et paré. Il faut faire attention aux métacharactères de la coquille (risque potentiel d'injection).

je recommande également les substitutions variables à double citation dans les conditions shell:

if [ -n "$var" ]; then

puisque quelque chose comme a-o ou un autre contenu dans la variable pourrait modifier vos arguments de test.

7
répondu MykennaC 2008-12-15 21:57:01
var='   a b c   '
trimmed=$(echo $var)
7
répondu ultr 2013-04-01 11:26:14

je voudrais simplement utiliser sed:

function trim
{
    echo "" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
}

a) exemple d'utilisation sur une chaîne de caractères à ligne simple

string='    wordA wordB  wordC   wordD    '
trimmed=$( trim "$string" )

echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"

sortie:

GIVEN STRING: |    wordA wordB  wordC   wordD    |
TRIMMED STRING: |wordA wordB  wordC   wordD|

B) exemple d'utilisation sur une chaîne multiligne

string='    wordA
   >wordB<
wordC    '
trimmed=$( trim "$string" )

echo -e "GIVEN STRING: |$string|\n"
echo "TRIMMED STRING: |$trimmed|"

sortie:

GIVEN STRING: |    wordAA
   >wordB<
wordC    |

TRIMMED STRING: |wordAA
   >wordB<
wordC|

c) note finale:

Si vous n'avez pas comme pour utiliser une fonction, pour mono-ligne chaîne vous pouvez simplement utiliser une commande "plus facile à se rappeler" comme:

echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'

exemple:

echo "   wordA wordB wordC   " | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'

sortie:

wordA wordB wordC

en utilisant ce qui précède sur Les Cordes multi-lignes fonctionneront aussi bien , mais s'il vous plaît noter qu'il coupera n'importe quel arrière/dirigeant l'espace multiple interne aussi bien, comme GuruM noté dans les commentaires

string='    wordAA
    >four spaces before<
 >one space before<    '
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'

sortie:

wordAA
>four spaces before<
>one space before<

alors si vous voulez bien garder ces espaces, veuillez utiliser la fonction au début de ma réponse!

d) explication de la syntaxe sed "trouver et remplacer" sur les chaînes multilignes utilisées à l'intérieur de la fonction trim:

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
}'
6
répondu Luca Borrione 2015-09-25 18:55:32
# Strip leading and trailing white space (new line inclusive).
trim(){
    [[ "" =~ ^[[:space:]]*(.*[^[:space:]])[[:space:]]*$ ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

ou

# Strip leading white space (new line inclusive).
ltrim(){
    [[ "" =~ ^[[:space:]]*(.*[^[:space:]]) ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

# Strip trailing white space (new line inclusive).
rtrim(){
    [[ "" =~ ^[[:space:]]*(.*[^[:space:]])[[:space:]]*$ ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "$(rtrim "$(ltrim "")")"
}

ou

# Strip leading and trailing specified characters.  ex: str=$(trim "$str" $'\n a')
trim(){
    if [ "" ]; then
        trim_chrs=""
    else
        trim_chrs="[:space:]"
    fi

    [[ "" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

ou

# Strip leading specified characters.  ex: str=$(ltrim "$str" $'\n a')
ltrim(){
    if [ "" ]; then
        trim_chrs=""
    else
        trim_chrs="[:space:]"
    fi

    [[ "" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

# Strip trailing specified characters.  ex: str=$(rtrim "$str" $'\n a')
rtrim(){
    if [ "" ]; then
        trim_chrs=""
    else
        trim_chrs="[:space:]"
    fi

    [[ "" =~ ^(.*[^"$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 "" "")" "")"
}

ou

Building upon moskit's Express...

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "`expr "" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"`"
}

ou

# Strip leading white space (new line inclusive).
ltrim(){
    printf "%s" "`expr "" : "^[[:space:]]*\(.*[^[:space:]]\)"`"
}

# Strip trailing white space (new line inclusive).
rtrim(){
    printf "%s" "`expr "" : "^\(.*[^[:space:]]\)[[:space:]]*$"`"
}

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "$(rtrim "$(ltrim "")")"
}
6
répondu NOYB 2017-05-03 05:52:30

Voici une fonction trim () qui atténue et normalise les espaces

#!/bin/bash
function trim {
    echo $*
}

echo "'$(trim "  one   two    three  ")'"
# 'one two three'

et une autre variante qui utilise des expressions régulières.

#!/bin/bash
function trim {
    local trimmed="$@"
    if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]
    then 
        trimmed=${BASH_REMATCH[1]}
    fi
    echo "$trimmed"
}

echo "'$(trim "  one   two    three  ")'"
# 'one   two    three'
5
répondu Nicholas Sushkin 2011-06-08 16:43:16

cela n'a pas le problème avec les globbings indésirables, aussi, l'espace blanc intérieur est non modifié (en supposant que $IFS est mis à la valeur par défaut, qui est ' \t\n' ).

il lit jusqu'à la première ligne (et ne l'inclut pas) ou la fin de la chaîne, selon la première de ces éventualités, et élimine tout mélange d'espace de tête et de queue et de caractères \t . Si vous voulez préserver plusieurs lignes (et aussi bandes de tête et de nouvelles traînées), utiliser read -r -d '' var << eof à la place; notez cependant que si votre entrée contient \neof , elle sera coupée juste avant. (D'autres formes d'espace blanc, à savoir \r , \f , et \v , sont et non , même si vous les ajoutez à $IFS.)

read -r var << eof
$var
eof
4
répondu Gregor 2012-06-04 04:52:35

Use AWK:

echo $var | awk '{gsub(/^ +| +$/,"")}1'
4
répondu ghostdog74 2015-09-25 18:45:24
Les assignations

ne tiennent pas compte des espaces de tête et de queue et peuvent donc être utilisées pour couper:

$ var=`echo '   hello'`; echo $var
hello
4
répondu evanx 2015-09-25 18:47:01
#!/bin/bash

function trim
{
    typeset trimVar
    eval trimVar="${}"
    read trimVar << EOTtrim
    $trimVar
EOTtrim
    eval =$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]
#[]
3
répondu Razor5900 2011-12-02 02:26:32

pour supprimer les espaces et les onglets de gauche au premier mot, entrez:

echo "     This is a test" | sed "s/^[ \t]*//"

cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html

3
répondu Steven Penny 2012-09-18 11:24:14

cela supprimera tous les espaces de votre chaîne,

 VAR2="${VAR2//[[:space:]]/}"

/ remplace la première occurrence et // toutes les occurrences d'Espaces Dans la chaîne. I. e. tous les espaces blancs sont remplacés par de – rien

3
répondu Alpesh Gediya 2013-05-29 12:09:01

cette garniture espaces multiples de l'avant et de l'extrémité

whatever=${whatever%% *}

whatever=${whatever#* }

2
répondu gretelmk2 2010-10-11 13:17:37

j'ai trouvé que j'avais besoin d'ajouter du code à partir d'une sortie sdiff pour le nettoyer:

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'

supprime les espaces de fuite et autres caractères invisibles.

2
répondu user1186515 2012-10-26 19:36:42

C'est la méthode la plus simple que j'ai vue. Il utilise seulement Bash, c'est seulement quelques lignes, le regexp est simple, et il correspond à toutes les formes d'espace:

if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then 
    test=${BASH_REMATCH[1]}
fi

voici un exemple de script pour le tester avec:

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."
2
répondu blujay 2014-04-28 04:25:24

j'ai créé les fonctions suivantes. Je ne suis pas sûr de comment portable printf est, mais la beauté de cette solution est que vous pouvez spécifier exactement ce qui est "espace blanc" en ajoutant plus de codes de caractères.

    iswhitespace()
    {
        n=`printf "%d\n" "''"`
        if (( $n != "13" )) && (( $n != "10" )) && (( $n != "32" )) && (( $n != "92" )) && (( $n != "110" )) && (( $n != "114" )); then
            return 0
        fi
        return 1
    }

    trim()
    {
        i=0
        str=""
        while (( i < ${#1} ))
        do
            char=${1:$i:1}
            iswhitespace "$char"
            if [ "$?" -eq "0" ]; then
                str="${str:$i}"
                i=${#1}
            fi
            (( i += 1 ))
        done
        i=${#str}
        while (( i > "0" ))
        do
            (( i -= 1 ))
            char=${str:$i:1}
            iswhitespace "$char"
            if [ "$?" -eq "0" ]; then
                (( i += 1 ))
                str="${str:0:$i}"
                i=0
            fi
        done
        echo "$str"
    }

#Call it like so
mystring=`trim "$mystring"`
2
répondu cmeub 2015-09-25 18:48:33