web-dev-qa-db-fra.com

Comment couper les espaces 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 est toujours exécuté car hg st imprime toujours au moins un caractère de nouvelle ligne.

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

ou

  • Existe-t-il un moyen standard de traiter ce problème?

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

819
too much php

Définissons une variable contenant les espaces de début, de fin et intermédiaires:

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 (notés [: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 uniquement:

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 finaux uniquement:

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 supprimer les espaces de début et de fin - chaînez le seds:

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 suit (pour les espaces finaux):

FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
946
MattyV

Une réponse simple est:

echo "   lol  " | xargs

Xargs fera le rognage pour vous. C'est une commande/programme, sans paramètre, retourne la chaîne coupée, aussi simple que cela!

Remarque: ceci ne supprime pas les espaces internes, donc "foo bar" reste inchangé. Cela ne devient PAS "foobar".

837
makevoid

Il existe une solution qui utilise uniquement les fonctions intégrées de Bash appelées caractères génériques :

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

Voici la même chose enveloppée 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 entre guillemets. par exemple.:

trim "   abc   "

Une bonne chose à propos de cette solution est qu’elle fonctionnera avec n’importe quel shell compatible POSIX.

Référence

309
bashfu

Bash a une fonctionnalité appelée expansion des paramètres, qui permet, entre autres, le remplacement de chaînes basé sur ce qu'on appelle patterns (les patterns ressemblent à des expressions régulières, mais il existe des différences et des limitations fondamentales ). [La ligne d'origine de flussence: Bash a des expressions régulières, mais elles sont bien cachées:]

Ce qui suit montre comment supprimer tout un espace (même de l'intérieur) d'une valeur de 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
73
user42092

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

Cela supprimera également les espaces en double:

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

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

48
rkachach

Dénudez un espace de début et un espace de fuite

trim()
{
    local trimmed="$1"

    # 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 all espaces de début et de fin

trim()
{
    local trimmed="$1"

    # 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'
47
Brian Cain

Vous pouvez couper simplement avec echo:

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'
38
VAmp

De la section du guide Bash sur globbing

Pour utiliser un extglob dans une extension de paramètre

 #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é encapsulée dans une fonction (REMARQUE: nécessité de citer la chaîne d'entrée transmise à 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=$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.
}

Usage:

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 pour qu'elle s'exécute dans un sous-shell, nous n'avons pas à nous soucier d'examiner l'option Shell actuelle pour extglob, nous pouvons simplement la définir sans affecter le Shell actuel. Cela simplifie énormément la fonction. Je mets également à jour les paramètres de position "en place", donc je n'ai même pas besoin d'une variable locale

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

alors:

$ 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
36
GuruM

Avec les fonctionnalités étendues de correspondance de modèle de Bash activées (shopt -s extglob), vous pouvez utiliser ceci:

{trimmed##*( )}

pour supprimer une quantité arbitraire d'espaces de début.

24
Mooshu

Je l'ai toujours fait avec sed

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

S'il existe une solution plus élégante, j'espère que quelqu'un la publiera.

22
Paul Tomblin

Vous pouvez supprimer des nouvelles lignes avec tr:

var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
    echo $var
done
20
Adam Rosenfield
# 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
18
flabdablet

Il y a beaucoup de réponses, mais je crois toujours que le script que je viens d'écrire mérite d'être mentionné pour les raisons suivantes:

  • il a été testé avec succès dans les shells bash/dash/busybox Shell
  • c'est extrêmement petit
  • il ne dépend pas de commandes externes et n'a pas besoin de se fourrer (-> utilisation rapide et faible des ressources)
  • cela fonctionne comme prévu:
    • il dépouille tous espaces et tabulations du début et de la fin, mais pas plus
    • important: il ne supprime rien du milieu de la chaîne (beaucoup de réponses le font), même les nouvelles lignes resteront
    • special: le "$*" joint plusieurs arguments en utilisant un espace. si vous voulez couper et afficher uniquement le premier argument, utilisez plutôt "$1"
    • si n'a pas de problèmes avec les modèles de noms de fichiers correspondants, etc.

Le scénario:

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

Usage:

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

Sortie:

>here     is
    something<
11
Daniel Alder

Vous pouvez utiliser old-school tr. Par exemple, cela renvoie le nombre de fichiers modifiés dans un référentiel git, espaces blancs supprimés.

MYVAR=`git ls-files -m|wc -l|tr -d ' '`
11
pojo

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##+( )}%%+( )}
10
gMale
# Strip leading and trailing white space (new line inclusive).
trim(){
    [[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
    printf "%s" "$BASH_REMATCH"
}

OR

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

OR

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

OR

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

OR

S'appuyant sur l'expruution de moskit ...

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

OR

# 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")")"
}
10
NOYB

J'ai vu des scripts simplement utiliser une affectation de variable pour faire le travail:

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

Les espaces sont automatiquement fusionnés et ajustés. Il faut faire attention aux métacaractères de Shell (risque d'injection potentiel).

Je recommanderais également de toujours citer deux fois les substitutions de variables dans les conditions de Shell:

if [ -n "$var" ]; then

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

8
MykennaC
var='   a b c   '
trimmed=$(echo $var)
7
ultr

Je voudrais simplement utiliser sed:

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

a) Exemple d'utilisation sur une chaîne d'une seule ligne

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'aimez pas utiliser une fonction, pour chaîne sur une seule ligne, vous pouvez simplement utiliser une commande "plus facile à mémoriser" 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

Utilisation de ce qui précède sur les chaînes multilignes fonctionneront également, mais veuillez noter que cela supprimera également tout espace interne multiple de fin/précédant également, comme GuruM l’a remarqué 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<

Donc si vous voulez garder ces espaces, utilisez 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 dans 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
}'
7
Luca Borrione

Utilisez AWK:

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

Pour supprimer des espaces et des tabulations de gauche à première Word, entrez:

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

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

5
Steven Penny

Voici une fonction trim () qui réduit 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
Nicholas Sushkin

Cela ne pose pas le problème de la suppression non souhaitée, mais l'espace blanc intérieur n'est pas modifié (en supposant que $IFS est défini sur la valeur par défaut, qui est ' \t\n').

Il lit jusqu'à la première nouvelle ligne (sans l'inclure) ou à la fin de la chaîne, selon la première éventualité, et supprime tout mélange d'espaces de début et de fin et de caractères \t. Si vous souhaitez conserver plusieurs lignes (et également supprimer les nouvelles lignes), utilisez 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 pas supprimées, même si vous les ajoutez à $ IFS.)

read -r var << eof
$var
eof
5
Gregor

Les affectations ignorent les espaces de début et de fin et peuvent donc être utilisées pour découper:

$ var=`echo '   hello'`; echo $var
hello
5
evanx

Cela supprimera tous les espaces de votre chaîne,

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

/ remplace la première occurrence et // toutes les occurrences de blancs dans la chaîne. C'est à dire. tous les espaces blancs sont remplacés par - rien

4
Alpesh Gediya

C'est la méthode la plus simple que j'ai vue. Il n'utilise que Bash, quelques lignes seulement, l'expression rationnelle est simple et correspond à toutes les formes d'espaces:

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

Voici un exemple de script pour le tester:

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."
4
blujay

Python a une fonction strip() qui fonctionne de manière identique à trim() de PHP. Nous pouvons donc faire un peu en ligne Python pour en faire un utilitaire facilement compréhensible:

alias trim='python -c "import sys; sys.stdout.write(sys.stdin.read().strip())"'

Cela supprimera les espaces de début et de fin (y compris les nouvelles lignes).

$ x=`echo -e "\n\t   \n" | trim`
$ if [ -z "$x" ]; then echo hi; fi
hi
3
brownhead

trim () supprime les espaces (et les tabulations, caractères non imprimables; je considère simplement les espaces pour plus de simplicité). Ma version d'une solution:

var="$(hg st -R "$path")" # I often like to enclose Shell output in double quotes
var="$(echo "${var}" | sed "s/\(^ *\| *\$\)//g")" # This is my suggestion
if [ -n "$var" ]; then
 echo "[${var}]"
fi

La commande 'sed' supprime uniquement les espaces blancs de début et de fin, mais elle peut également être transmise à la première commande, ce qui entraîne:

var="$(hg st -R "$path" | sed "s/\(^ *\| *\$\)//g")"
if [ -n "$var" ]; then
 echo "[${var}]"
fi
3
Avenger
#!/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]
#[]
3
Razor5900

J'ai trouvé que je devais ajouter du code à partir d'une sortie désordonnée sdiff afin de 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'

Cela supprime les espaces de fin et autres caractères invisibles.

3
user1186515

Utilisation:

trim() {
    local orig="$1"
    local trmd=""
    while true;
    do
        trmd="${orig#[[:space:]]}"
        trmd="${trmd%[[:space:]]}"
        test "$trmd" = "$orig" && break
        orig="$trmd"
    done
    printf -- '%s\n' "$trmd"
}
  • Cela fonctionne sur toutes sortes d'espaces, y compris newline,
  • Il n'a pas besoin de modifier shopt.
  • Il préserve les espaces, y compris les nouvelles lignes.

Test unitaire (pour examen manuel):

#!/bin/bash

. trim.sh

enum() {
    echo "   a b c"
    echo "a b c   "
    echo "  a b c "
    echo " a b c  "
    echo " a  b c  "
    echo " a  b  c  "
    echo " a      b  c  "
    echo "     a      b  c  "
    echo "     a  b  c  "
    echo " a  b  c      "
    echo " a  b  c      "
    echo " a N b  c  "
    echo "N a N b  c  "
    echo " Na  b  c  "
    echo " a  b  c N "
    echo " a  b  c  N"
}

xcheck() {
    local testln result
    while IFS='' read testln;
    do
        testln=$(tr N '\n' <<<"$testln")
        echo ": ~~~~~~~~~~~~~~~~~~~~~~~~~ :" >&2
        result="$(trim "$testln")"
        echo "testln='$testln'" >&2
        echo "result='$result'" >&2
    done
}

enum | xcheck
3
Alois Mahdal

J'ai créé les fonctions suivantes. Je ne sais pas trop à quel point printf est portable, mais la beauté de cette solution est que vous pouvez spécifier exactement ce qu'est un "espace blanc" en ajoutant plus de codes de caractères.

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

    trim()
    {
        i=0
        str="$1"
        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"`
3
cmeub

Supprimer des espaces dans un espace:

(text) | fmt -su
2
gardziol

J'avais besoin de couper les espaces d'un script lorsque la variable IFS était définie sur autre chose. S'appuyant sur Perl a fait le tour:

# trim() { echo $1; } # This doesn't seem to work, as it's affected by IFS

trim() { echo "$1" | Perl -p -e 's/^\s+|\s+$//g'; }

strings="after --> , <-- before,  <-- both -->  "

OLD_IFS=$IFS
IFS=","
for str in ${strings}; do
  str=$(trim "${str}")
  echo "str= '${str}'"
done
IFS=$OLD_IFS
2
TrinitronX
var="  a b  "
echo "$(set -f; echo $var)"

>a b
2
davide

Utilisez ce simple Bash expansion des paramètres:

$ x=" a z     e r ty "
$ echo "START[${x// /}]END"
START[azerty]END
2
Gilles Quenot

Utilisation:

var=`expr "$var" : "^\ *\(.*[^ ]\)\ *$"`

Il supprime les espaces de début et de fin et constitue la solution la plus élémentaire, à mon avis. Pas Bash intégré, mais 'expr' fait partie de coreutils, donc au moins aucun utilitaire autonome n'est nécessaire comme sed ou AWK .

2
moskit

Cette coupe plusieurs espaces de l'avant et la fin

whatever=${whatever%% *}

whatever=${whatever#* }

2
gretelmk2

Encore une autre solution avec tests unitaires qui ajuste $IFS à partir de stdin, et fonctionne avec tout séparateur d'entrée (même $'\0'):

ltrim()
{
    # Left-trim $IFS from stdin as a single line
    # $1: Line separator (default NUL)
    local trimmed
    while IFS= read -r -d "${1-}" -u 9
    do
        if [ -n "${trimmed+defined}" ]
        then
            printf %s "$REPLY"
        else
            printf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"
        fi
        printf "${1-\x00}"
        trimmed=true
    done 9<&0

    if [[ $REPLY ]]
    then
        # No delimiter at last line
        if [ -n "${trimmed+defined}" ]
        then
            printf %s "$REPLY"
        else
            printf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"
        fi
    fi
}

rtrim()
{
    # Right-trim $IFS from stdin as a single line
    # $1: Line separator (default NUL)
    local previous last
    while IFS= read -r -d "${1-}" -u 9
    do
        if [ -n "${previous+defined}" ]
        then
            printf %s "$previous"
            printf "${1-\x00}"
        fi
        previous="$REPLY"
    done 9<&0

    if [[ $REPLY ]]
    then
        # No delimiter at last line
        last="$REPLY"
        printf %s "$previous"
        if [ -n "${previous+defined}" ]
        then
            printf "${1-\x00}"
        fi
    else
        last="$previous"
    fi

    right_whitespace="${last##*[!$IFS]}"
    printf %s "${last%$right_whitespace}"
}

trim()
{
    # Trim $IFS from individual lines
    # $1: Line separator (default NUL)
    ltrim ${1+"$@"} | rtrim ${1+"$@"}
}
1
l0b0

Je devais tester le résultat (numérique) à partir d'une commande, mais il semblait que la variable avec le résultat contenait des espaces et des caractères non imprimables. Par conséquent, même après un "trim", la comparaison était erronée. Je l'ai résolu en extrayant la partie numérique de la variable:

numerical_var=$(echo ${var_with_result_from_command} | grep -o "[0-9]*")
0
Olivier Meurice