it-swarm.com.de

Wie schneide ich Leerzeichen aus einer Bash-Variablen heraus?

Ich habe ein Shell-Skript mit diesem Code:

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

Der bedingte Code wird jedoch immer ausgeführt, da hg st immer mindestens ein Zeilenumbruchzeichen ausgibt.

  • Gibt es eine einfache Möglichkeit, Leerzeichen aus $var zu entfernen (wie trim() in PHP )?

oder

  • Gibt es eine Standardmethode für den Umgang mit diesem Problem?

Ich könnte sed oder AWK verwenden, aber ich würde gerne denken, dass es eine elegantere Lösung für dieses Problem gibt.

819
too much php

Definieren wir eine Variable, die führende, nachfolgende und dazwischenliegende Leerzeichen enthält:

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

So entfernen Sie alle Leerzeichen (gekennzeichnet durch [:space:] in 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

So entfernen Sie nur führende Leerzeichen:

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

So entfernen Sie nur nachfolgende Leerzeichen:

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

So entfernen Sie führende und nachfolgende Leerzeichen - verketten Sie die 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

Alternativ können Sie echo -e "${FOO}" | sed ... durch sed ... <<<${FOO} ersetzen, wenn Ihre Bash dies unterstützt (für abschließende Leerzeichen):

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

Eine einfache Antwort lautet:

echo "   lol  " | xargs

Xargs erledigt den Zuschnitt für Sie. Es ist ein Befehl/Programm, keine Parameter, gibt den abgeschnittenen String zurück, so einfach ist das!

Hinweis: Dadurch werden die internen Leerzeichen nicht entfernt, sodass "foo bar" gleich bleibt. Es wird NICHT "foobar".

837
makevoid

Es gibt eine Lösung, die nur integrierte Bash-Funktionen verwendet, die als Platzhalter bezeichnet werden:

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

Hier ist das Gleiche in einer Funktion verpackt:

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

Sie übergeben die zu trimmende Zeichenfolge in Anführungszeichen. z.B.:

trim "   abc   "

Das Schöne an dieser Lösung ist, dass sie mit jeder POSIX-kompatiblen Shell funktioniert.

Referenz

309
bashfu

Bash hat eine Funktion namens Parametererweiterung, die unter anderem das Ersetzen von Zeichenfolgen basierend auf sogenannten Mustern (Mustern ähneln regulären Ausdrücken, aber es gibt grundlegende Unterschiede und Einschränkungen ). [Flussences ursprüngliche Zeile: Bash hat reguläre Ausdrücke, aber sie sind gut versteckt:]

Im Folgenden wird veranschaulicht, wie alle Leerzeichen (auch aus dem Innenraum) aus einem variablen Wert entfernt werden.

$ 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

So entfernen Sie alle Leerzeichen am Anfang und am Ende einer Zeichenfolge (einschließlich der Zeichen am Zeilenende):

echo $variable | xargs echo -n

Dadurch werden auch doppelte Leerzeichen entfernt:

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

Produziert: 'Diese Saite hat viele Leerzeichen'

48
rkachach

Entfernen Sie ein führendes und ein hinteres Leerzeichen

trim()
{
    local trimmed="$1"

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

    echo "$trimmed"
}

Zum Beispiel:

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

Ausgabe:

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

Strip all führende und nachfolgende Leerzeichen

trim()
{
    local trimmed="$1"

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

    echo "$trimmed"
}

Zum Beispiel:

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

Ausgabe:

'two leading', 'two trailing', 'two leading and two trailing'
47
Brian Cain

Sie können einfach mit echo trimmen:

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'
38
VAmp

Vom Bash Guide Abschnitt auf Globbing

Verwendung eines Extglobs in einer Parametererweiterung

 #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  

Hier ist dieselbe Funktionalität, die in einer Funktion enthalten ist (HINWEIS: An die Funktion übergebene Eingabezeichenfolge muss in Anführungszeichen gesetzt werden):

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

Verwendungszweck:

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

Wenn wir die auszuführende Funktion in einer Subshell ändern, müssen wir uns nicht um die Prüfung der aktuellen Shell-Option für extglob kümmern, sondern können sie einfach festlegen, ohne die aktuelle Shell zu beeinflussen. Dies vereinfacht die Funktion enorm. Ich aktualisiere auch die Positionsparameter "an Ort und Stelle", sodass ich nicht einmal eine lokale Variable benötige

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

damit:

$ 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

Wenn die erweiterten Pattern-Matching-Funktionen von Bash aktiviert sind (shopt -s extglob), können Sie Folgendes verwenden:

{trimmed##*( )}

um beliebig viele führende Leerzeichen zu entfernen.

24
Mooshu

Ich habe es immer mit sed gemacht

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

Wenn es eine elegantere Lösung gibt, hoffe ich, dass jemand sie veröffentlicht.

22
Paul Tomblin

Sie können Zeilenumbrüche mit tr löschen:

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

Es gibt viele Antworten, aber ich glaube immer noch, dass mein gerade geschriebenes Drehbuch es wert ist, erwähnt zu werden, weil:

  • es wurde erfolgreich in der Shell bash/dash/busybox Shell getestet
  • es ist extrem klein
  • es hängt nicht von externen Befehlen ab und muss nicht gegabelt werden (-> schneller und geringer Ressourcenverbrauch)
  • es funktioniert wie erwartet:
    • es entfernt alle Leerzeichen und Tabulatoren vom Anfang und Ende, aber nicht mehr
    • wichtig: Es wird nichts aus der Mitte der Zeichenfolge entfernt (viele andere Antworten tun dies), auch Zeilenumbrüche bleiben erhalten
    • besonderheit: Der "$*" verbindet mehrere Argumente mit einem Leerzeichen. Wenn Sie nur das erste Argument zuschneiden und ausgeben möchten, verwenden Sie stattdessen "$1"
    • wenn keine Probleme mit übereinstimmenden Dateinamenmustern etc

Das Drehbuch:

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

Verwendungszweck:

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

Ausgabe:

>here     is
    something<
11
Daniel Alder

Sie können old-school tr verwenden. Dies gibt beispielsweise die Anzahl der geänderten Dateien in einem Git-Repository zurück, wobei Leerzeichen entfernt werden.

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

Das hat bei mir funktioniert:

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>

Um dies für dasselbe Ergebnis auf weniger Zeilen zu setzen:

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

Aufbauend auf Moskits expr Soulution ...

# 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

Ich habe gesehen, dass Skripte nur die Variablenzuweisung verwenden, um die Arbeit zu erledigen:

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

Whitespace wird automatisch zusammengeführt und zugeschnitten. Man muss auf Shell-Metazeichen achten (potentielles Injektionsrisiko).

Ich würde auch empfehlen, Variablensubstitutionen in Shell-Bedingungen immer in doppelte Anführungszeichen zu setzen:

if [ -n "$var" ]; then

da so etwas wie ein -o oder ein anderer Inhalt in der Variablen Ihre Testargumente ändern könnte.

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

Ich würde einfach sed verwenden:

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

a) Anwendungsbeispiel für einzeilige Zeichenfolge

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

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

Ausgabe:

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

b) Anwendungsbeispiel für eine mehrzeilige Zeichenfolge

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

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

Ausgabe:

GIVEN STRING: |    wordAA
   >wordB<
wordC    |

TRIMMED STRING: |wordAA
   >wordB<
wordC|

c) Schlussnote:
Wenn Sie keine Funktion verwenden möchten, können Sie für einzeilige Zeichenfolge einfach einen "leichter zu merkenden" Befehl wie den folgenden verwenden:

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

Beispiel:

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

Ausgabe:

wordA wordB wordC

Verwenden Sie das oben genannte on Mehrzeilige Zeichenfolgen funktionieren auch, aber beachten Sie, dass es auch alle nachgestellten/führenden internen Mehrfachzeichen schneidet, wie GuruM in den Kommentaren bemerkt hat

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

Ausgabe:

wordAA
>four spaces before<
>one space before<

Wenn Sie diese Leerzeichen behalten möchten, verwenden Sie bitte die Funktion am Anfang meiner Antwort!

d) EXPLANATION der sed-Syntax "find and replace" für mehrzeilige Zeichenfolgen, die in der Funktion trim verwendet werden:

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

Verwenden Sie AWK:

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

Geben Sie Folgendes ein, um Leerzeichen und Tabulatoren vom linken zum ersten Wort zu entfernen:

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

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

5
Steven Penny

Hier ist eine trim () - Funktion, die Leerzeichen schneidet und normalisiert

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

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

Und eine andere Variante, die reguläre Ausdrücke verwendet.

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

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

Dies hat nicht das Problem mit ungewolltem Globbing, und der innere Leerraum bleibt unverändert (vorausgesetzt, $IFS ist auf den Standardwert ' \t\n' eingestellt).

Es liest bis zur ersten neuen Zeile (und schließt diese nicht ein) oder bis zum Ende der Zeichenkette, je nachdem, was zuerst eintritt, und entfernt jede Mischung aus führenden und nachfolgenden Leerzeichen und \t -Zeichen. Wenn Sie mehrere Zeilen beibehalten möchten (und auch führende und nachfolgende Zeilen entfernen möchten), verwenden Sie stattdessen read -r -d '' var << eof. Beachten Sie jedoch, dass Ihre Eingabe, wenn sie \neof enthält, kurz zuvor abgeschnitten wird. (Andere Formen von Leerzeichen, nämlich \r, \f und \v, werden nicht entfernt, auch wenn Sie sie zu $ ​​IFS hinzufügen.)

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

Zuweisungen ignorieren führende und nachfolgende Leerzeichen und können daher zum Trimmen verwendet werden:

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

Dadurch werden alle Leerzeichen aus Ihrem String entfernt.

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

/ ersetzt das erste Vorkommen und // alle Vorkommen von Leerzeichen in der Zeichenfolge. Das heißt Alle Leerzeichen werden durch - nichts ersetzt

4
Alpesh Gediya

Dies ist die einfachste Methode, die ich je gesehen habe. Es wird nur Bash verwendet, es sind nur ein paar Zeilen, der reguläre Ausdruck ist einfach und es werden alle Arten von Leerzeichen verwendet:

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

Hier ist ein Beispielskript zum Testen:

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 hat eine Funktion strip(), die identisch mit der Funktion trim() von PHP funktioniert. Daher können wir einfach ein kleines Inline-Programm Python ausführen, um ein leicht verständliches Hilfsprogramm dafür zu erstellen:

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

Dadurch werden führende und nachfolgende Leerzeichen (einschließlich Zeilenumbrüche) abgeschnitten.

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

trim () entfernt Leerzeichen (und Tabulatoren, nicht druckbare Zeichen; ich betrachte der Einfachheit halber nur Leerzeichen). Meine Version einer Lösung:

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

Der Befehl 'sed' schneidet nur führende und nachfolgende Leerzeichen ab, kann aber auch an den ersten Befehl weitergeleitet werden. Dies führt zu:

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

Ich stellte fest, dass ich Code aus einer unordentlichen sdiff Ausgabe hinzufügen musste, um ihn zu bereinigen:

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'

Dadurch werden die nachgestellten Leerzeichen und andere unsichtbare Zeichen entfernt.

3
user1186515

Verwenden:

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"
}
  • Es funktioniert auf allen Arten von Whitespace, einschließlich Newline,
  • Shopt muss nicht geändert werden.
  • Es werden Leerzeichen (einschließlich Zeilenvorschub) im Inneren beibehalten.

Unit Test (zur manuellen Überprüfung):

#!/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

Ich habe folgende Funktionen erstellt. Ich bin nicht sicher, wie portabel printf ist, aber das Schöne an dieser Lösung ist, dass Sie durch Hinzufügen weiterer Zeichencodes genau angeben können, was "Leerraum" ist.

    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

Leerzeichen zu einem Leerzeichen entfernen:

(text) | fmt -su
2
gardziol

Ich musste Leerzeichen aus einem Skript entfernen, wenn die Variable IFS auf einen anderen Wert gesetzt war. Unter Berufung auf Perl hat es geschafft:

# 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

Verwenden Sie diese einfache Bash Parametererweiterung:

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

Verwenden:

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

Es entfernt führende und nachfolgende Leerzeichen und ist meiner Meinung nach die grundlegendste Lösung. Nicht in Bash integriert, aber 'expr' ist ein Teil von coreutils, daher werden zumindest keine eigenständigen Dienstprogramme wie sed oder AWK benötigt.

2
moskit

Dies schneidet mehrere Räume der Front und des Endes ab

whatever=${whatever%% *}

whatever=${whatever#* }

2
gretelmk2

Noch eine andere Lösung mit Komponententests , die $IFS von stdin abschneidet und mit jedem Eingabetrennzeichen (sogar $'\0') funktioniert:

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+"[email protected]"} | rtrim ${1+"[email protected]"}
}
1
l0b0

Ich musste das Ergebnis (numerisch) eines Befehls testen, aber es schien, dass die Variable mit dem Ergebnis Leerzeichen und einige nicht druckbare Zeichen enthielt. Daher war der Vergleich auch nach einem "Beschnitt" fehlerhaft. Ich habe es gelöst, indem ich den numerischen Teil aus der Variablen extrahiert habe:

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