Ik heb een shellscript met deze code:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Maar de voorwaardelijke code wordt altijd uitgevoerd, omdat hg st
altijd ten minste één teken voor een nieuwe regel afdrukt.
- Is er een eenvoudige manier om witruimte te verwijderen van
$var
(zoalstrim()
in PHP)?
of
- Is er een standaardmanier om met dit probleem om te gaan?
Ik zou sedof AWK, maar ik zou graag denken dat er een elegantere oplossing voor dit probleem is.
Antwoord 1, autoriteit 100%
Een eenvoudig antwoord is:
echo " lol " | xargs
Xargszal het bijsnijden voor je doen. Het is één commando/programma, geen parameters, geeft de getrimde string terug, zo simpel is het!
Opmerking: hiermee worden niet alle interne spaties verwijderd, dus "foo bar"
blijft hetzelfde; het wordt NIET "foobar"
. Meerdere spaties worden echter samengevoegd tot enkele spaties, dus "foo bar"
wordt "foo bar"
. Bovendien worden tekens aan het einde van de regel niet verwijderd.
Antwoord 2, autoriteit 90%
Laten we een variabele definiëren die voorloop-, volg- en tussenliggende witruimte bevat:
FOO=' test test test '
echo -e "FOO='${FOO}'"
# > FOO=' test test test '
echo -e "length(FOO)==${#FOO}"
# > length(FOO)==16
Hoe alle WhiteSpace verwijderen (aangegeven met [: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
Alleen voorloopwhites verwijderen:
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
Alleen Trailing WhiteSpace verwijderen:
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
Hoe verwijdert u zowel toonaangevende als achterliggende spaties – ketting de 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
Als je bash dit ondersteunt, kun je ook echo -e "${FOO}" | sed ...
met sed ... <<<${FOO}
, zoals zo (voor achterliggende witruimte):
FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
Antwoord 3, autoriteit 35%
Er is een oplossing die alleen ingebouwde Bash gebruikt, genaamd jokertekens:
var=" abc "
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "===$var==="
Hier is hetzelfde verpakt in een functie:
trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "$var"
}
Je geeft de tekenreeks die moet worden bijgesneden, tussen aanhalingstekens door. bijv.:
trim " abc "
Het leuke van deze oplossing is dat deze werkt met elke POSIX-compatibele shell.
Referentie
4, Autoriteit 6%
Om alle ruimtes vanaf het begin en het einde van een tekenreeks (inclusief einde van lijntekens) te verwijderen:
echo $variable | xargs echo -n
Hiermee wordt dubbele spaties ook weergegeven:
echo " this string has a lot of spaces " | xargs echo -n
produceert: ‘Deze string heeft veel spaties’
5, Autoriteit 5%
Strip één toonaangevende en één trailingruimte
trim()
{
local trimmed="$1"
# Strip leading space.
trimmed="${trimmed## }"
# Strip trailing space.
trimmed="${trimmed%% }"
echo "$trimmed"
}
Bijvoorbeeld:
test1="$(trim " one leading")"
test2="$(trim "one trailing ")"
test3="$(trim " one leading and one trailing ")"
echo "'$test1', '$test2', '$test3'"
Uitgang:
'one leading', 'one trailing', 'one leading and one trailing'
Strip allevoor- en achterspaties
trim()
{
local trimmed="$1"
# Strip leading spaces.
while [[ $trimmed == ' '* ]]; do
trimmed="${trimmed## }"
done
# Strip trailing spaces.
while [[ $trimmed == *' ' ]]; do
trimmed="${trimmed%% }"
done
echo "$trimmed"
}
Bijvoorbeeld:
test4="$(trim " two leading")"
test5="$(trim "two trailing ")"
test6="$(trim " two leading and two trailing ")"
echo "'$test4', '$test5', '$test6'"
Uitvoer:
'two leading', 'two trailing', 'two leading and two trailing'
Antwoord 6, autoriteit 4%
Uit de Bash Guide-sectie over globbing
Een extglob gebruiken in een parameteruitbreiding
#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 is dezelfde functionaliteit verpakt in een functie (OPMERKING: invoertekenreeks die aan functie is doorgegeven moet worden geciteerd):
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.
}
Gebruik:
string=" abc def ghi ";
#need to quote input-string to preserve internal white-space if any
trimmed=$(trim "$string");
echo "$trimmed";
Als we de functie wijzigen om in een subshell te worden uitgevoerd, hoeven we ons geen zorgen te maken over het onderzoeken van de huidige Shell-optie voor extgglob, kunnen we het gewoon instellen zonder de huidige schaal te beïnvloeden. Dit vereenvoudigt de functie enorm. Ik update ook de positionele parameters “op zijn plaats”, dus ik heb zelfs geen lokale variabele nodig
trim() {
shopt -s extglob
set -- "${1##+([[:space:]])}"
printf "%s" "${1%%+([[:space:]])}"
}
Dus:
$ 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
7, Autoriteit 4%
U kunt simpelweg trimmen met echo
:
foo=" qsdqsd qsdqs q qs "
# Not trimmed
echo \'$foo\'
# Trim
foo=`echo $foo`
# Trimmed
echo \'$foo\'
8, Autoriteit 2%
Ik heb het altijd gedaan met sed
var=`hg st -R "$path" | sed -e 's/ *$//'`
Als er een elegante oplossing is, hoop ik dat iemand het pooit.
9, Autoriteit 2%
Met BASH’s Extended Pattern Matching-functies ingeschakeld (shopt -s extglob
), kunt u dit gebruiken:
{trimmed##*( )}
om een willekeurige hoeveelheid leidende ruimtes te verwijderen.
10, Autoriteit 2%
U kunt newlines verwijderen met tr
:
var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
echo $var
done
11, Autoriteit 2%
# 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
12
Er zijn veel antwoorden, maar ik geloof nog steeds dat mijn Just-geschreven script de moeite waard is om te worden vermeld, omdat:
- Het is succesvol getest in de Shells Bash / Dash / Seepbox Shell
- Het is extreem klein
- Het is niet afhankelijk van externe opdrachten en hoeft niet te vork (- & GT; snel en laag resource-gebruik)
- Het werkt zoals verwacht:
- het stript alle spaties en tabbladen vanaf het begin en einde, maar niet meer
- BELANGRIJK: het verwijdert niets uit het midden van de tekenreeks (veel andere antwoorden), zelfs newlines blijven
- speciaal: de
"$*"
voegt meerdere argumenten samen met één spatie. als u wilt trimmen & voer alleen het eerste argument uit, gebruik in plaats daarvan"$1"
- als er geen problemen zijn met het matchen van bestandsnaampatronen enz.
Het script:
trim() {
local s2 s="$*"
until s2="${s#[[:space:]]}"; [ "$s2" = "$s" ]; do s="$s2"; done
until s2="${s%[[:space:]]}"; [ "$s2" = "$s" ]; do s="$s2"; done
echo "$s"
}
Gebruik:
mystring=" here is
something "
mystring=$(trim "$mystring")
echo ">$mystring<"
Uitvoer:
>here is
something<
Antwoord 13
Als je shopt -s extglob
hebt ingeschakeld, dan is het volgende een nette oplossing.
Dit werkte voor mij:
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>
Om dat op minder regels te zetten voor hetzelfde resultaat:
text=" trim my edges "
trimmed=${${text##+( )}%%+( )}
Antwoord 14
# Strip leading and trailing white space (new line inclusive).
trim(){
[[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
printf "%s" "$BASH_REMATCH"
}
OF
# 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")")"
}
OF
# 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]}"
}
OF
# 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")"
}
OF
Voortbouwend op de expr-oplossing van moskit…
# Strip leading and trailing white space (new line inclusive).
trim(){
printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"`"
}
OF
# 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")")"
}
Antwoord 15
Dit is wat ik deed en werkte perfect en zo eenvoudig:
the_string=" test"
the_string=`echo $the_string`
echo "$the_string"
Uitvoer:
test
Antwoord 16
Je kunt ouderwetse tr
gebruiken. Dit retourneert bijvoorbeeld het aantal gewijzigde bestanden in een git-repository, witruimten gestript.
MYVAR=`git ls-files -m|wc -l|tr -d ' '`
Antwoord 17
Gebruik AWK:
echo $var | awk '{gsub(/^ +| +$/,"")}1'
Antwoord 18
Ik heb gezien dat scripts alleen variabele toewijzing gebruiken om het werk te doen:
$ xyz=`echo -e 'foo \n bar'`
$ echo $xyz
foo bar
Witruimte wordt automatisch samengevoegd en bijgesneden. Men moet voorzichtig zijn met shell-metakarakters (potentieel injectierisico).
Ik zou ook aanraden om variabele vervangingen altijd dubbel te citeren in shell-voorwaarden:
if [ -n "$var" ]; then
aangezien iets als a -o of andere inhoud in de variabele je testargumenten zou kunnen wijzigen.
Antwoord 19
Ik zou gewoon sed gebruiken:
function trim
{
echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
}
a) Voorbeeld van gebruik op string met één regel
string=' wordA wordB wordC wordD '
trimmed=$( trim "$string" )
echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"
Uitvoer:
GIVEN STRING: | wordA wordB wordC wordD |
TRIMMED STRING: |wordA wordB wordC wordD|
b) Voorbeeld van gebruik op string met meerdere regels
string=' wordA
>wordB<
wordC '
trimmed=$( trim "$string" )
echo -e "GIVEN STRING: |$string|\n"
echo "TRIMMED STRING: |$trimmed|"
Uitvoer:
GIVEN STRING: | wordAA
>wordB<
wordC |
TRIMMED STRING: |wordAA
>wordB<
wordC|
c) Laatste opmerking:
Als u een functie niet wilt gebruiken, kunt u voor eenregelige tekenreekseenvoudig een “gemakkelijker te onthouden” opdracht gebruiken, zoals:
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
Voorbeeld:
echo " wordA wordB wordC " | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
Uitvoer:
wordA wordB wordC
Het gebruik van het bovenstaande op strings met meerdere regels werkt ook, maar houd er rekening mee dat het ook alle achter-/voorloopinterne meervoudige spatie weghaalt, zoals GuruM opmerkte in de opmerkingen
string=' wordAA
>four spaces before<
>one space before< '
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'
Uitvoer:
wordAA
>four spaces before<
>one space before<
Dus als je het erg vindt om die spaties te behouden, gebruik dan de functie aan het begin van mijn antwoord!
d) UITLEGvan de sed-syntaxis “vinden en vervangen” op strings met meerdere regels die worden gebruikt in de functie 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
}'
Antwoord 20
var=' a b c '
trimmed=$(echo $var)
Antwoord 21
Hier is een trim()-functie die witruimte bijsnijdt en normaliseert
#!/bin/bash
function trim {
echo $*
}
echo "'$(trim " one two three ")'"
# 'one two three'
en een andere variant die reguliere uitdrukkingen gebruikt.
#!/bin/bash
function trim {
local trimmed="$@"
if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]
then
trimmed=${BASH_REMATCH[1]}
fi
echo "$trimmed"
}
echo "'$(trim " one two three ")'"
# 'one two three'
22
Om spaties en tabbladen van links naar het eerste woord te verwijderen, voert u in:
echo " This is a test" | sed "s/^[ \t]*//"
cyberciti.biz/tips/delete- Leading-spaces-front-of-eeds-word.html
23
Hiermee wordt alle witruimtes uit uw string verwijderd,
VAR2="${VAR2//[[:space:]]/}"
/
Vervangt de eerste voorval en //
alle voorvallen van witvakken in de tekenreeks. D.w.z. Alle witte ruimtes worden vervangen door – niets
24
Dit is de eenvoudigste methode die ik heb gezien. Het gebruikt alleen BASH, het is maar een paar regels, het regexp is eenvoudig, en het komt overeen met alle vormen van witruimte:
if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then
test=${BASH_REMATCH[1]}
fi
Hier is een voorbeeldscript om het te testen met:
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."
Antwoord 25
Toewijzingen negeren voorloop- en volgspaties en kunnen als zodanig worden gebruikt om bij te snijden:
$ var=`echo ' hello'`; echo $var
hello
Antwoord 26
Dit heeft niet het probleem met ongewenste globbing, ook is de interne witruimte ongewijzigd (ervan uitgaande dat $IFS
is ingesteld op de standaardwaarde, namelijk ' \t\n'
).
Het leest tot aan de eerste nieuwe regel (en bevat deze niet) of het einde van de tekenreeks, wat het eerst komt, en verwijdert elke combinatie van voorloop- en volgspaties en \t
-tekens. Als u meerdere regels wilt behouden (en ook voorloop- en volgregels wilt verwijderen), gebruik dan read -r -d '' var << eof
in plaats daarvan; houd er echter rekening mee dat als uw invoer toevallig \neof
bevat, deze vlak daarvoor wordt afgebroken. (Andere vormen van witruimte, namelijk \r
, \f
en \v
, worden nietverwijderd, zelfs als je ze toevoegt aan $IFS.)
read -r var << eof
$var
eof
Antwoord 27
Python heeft een functie strip()
die identiek werkt aan PHP’s trim()
, dus we kunnen een beetje inline Python doen om hiervoor een gemakkelijk te begrijpen hulpprogramma te maken :
alias trim='python -c "import sys; sys.stdout.write(sys.stdin.read().strip())"'
Hiermee worden voorloop- en achterliggende witruimte bijgesneden (inclusief nieuwe regels).
$ x=`echo -e "\n\t \n" | trim`
$ if [ -z "$x" ]; then echo hi; fi
hi
Antwoord 28
Spaties naar één spatie verwijderen:
(text) | fmt -su
Antwoord 29
Ik moest de witruimte van een script inkorten toen de variabele IFS
op iets anders was ingesteld. Vertrouwen op Perldeed de truc:
# 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