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
(commetrim()
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.
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})"
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"
.
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
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
vous pouvez couper simplement avec echo
:
foo=" qsdqsd qsdqs q qs "
# Not trimmed
echo \'$foo\'
# Trim
foo=`echo $foo`
# Trimmed
echo \'$foo\'
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'
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"
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
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.
vous pouvez supprimer les nouvelles lignes avec tr
:
var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
echo $var
done
# 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
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.
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<
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 ' '`
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##+( )}%%+( )}
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.
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
}'
# 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 "")")"
}
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'
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
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
#!/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]
#[]
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
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
cette garniture espaces multiples de l'avant et de l'extrémité
whatever=${whatever%% *}
whatever=${whatever#* }
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.
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."
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"`