Jak usunąć spacje ze zmiennych powłoki?

15

W wierszu polecenia wykonałem następujące czynności:

$ text="name with space"
$ echo $text
name with space

Próbuję użyć tr -d ' 'do usunięcia spacji i uzyskać wynik:

namewithspace

Próbowałem kilku rzeczy, takich jak:

text=echo $text | tr -d ' '

Jak dotąd brak szczęścia, więc mam nadzieję, że cudowni ludzie mogą pomóc!

użytkownik3347022
źródło

Odpowiedzi:

45

W Bash możesz używać wbudowanej manipulacji ciągiem Bash. W takim przypadku możesz wykonać:

> text="some text with spaces"
> echo "${text// /}"
sometextwithspaces

Więcej informacji na temat operatorów manipulacji ciągami można znaleźć na stronie http://tldp.org/LDP/abs/html/string-manipulation.html

Jednak oryginalna strategia również działałaby, twoja składnia jest nieco odległa:

> text2=$(echo $text | tr -d ' ')
> echo $text2
sometextwithspaces
Steven D.
źródło
Nawet o tym nie myślałem, pracowałem nad tym w nastroju! Świetna odpowiedź!
user3347022,
11

W ogóle nie potrzebujesz echopolecenia, zamiast tego użyj tutaj Ciąg znaków:

text=$(tr -d ' ' <<< "$text")

Z ciekawości sprawdziłem, ile czasu zajmuje tak trywialne zadanie dla różnych narzędzi. Oto wyniki posortowane od najwolniejszego do najszybszego:

abc="some text with spaces"

$ time (for i in {1..1000}; do def=$(echo $abc | tr -d ' '); done)
0.76s user 1.85s system 52% cpu 4.976 total

$ time (for i in {1..1000}; do def=$(awk 'gsub(" ","")' <<< $abc); done)
1.09s user 2.69s system 88% cpu 4.255 total

$ time (for i in {1..1000}; do def=$(awk '$1=$1' OFS="" <<< $abc); done)
1.02s user 1.75s system 69% cpu 3.968 total

$ time (for i in {1..1000}; do def=$(sed 's/ //g' <<< $abc); done)
0.85s user 1.95s system 76% cpu 3.678 total

$ time (for i in {1..1000}; do def=$(tr -d ' ' <<< $abc); done)
0.73s user 2.04s system 85% cpu 3.244 total

$ time (for i in {1..1000}; do def=${abc// /}; done)
0.03s user 0.00s system 59% cpu 0.046 total

Operacja czystej powłoki jest zdecydowanie najszybsza, co nie jest zaskakujące, ale co naprawdę imponuje, że jest ponad 100 razy szybsza niż najwolniejsze polecenie!

jimmij
źródło
To nie zawsze jest prawda stackoverflow.com/q/14967299
Steven Penny
5

Po prostu zmodyfikuj zmienną tekstową jak poniżej.

text=$(echo $text | tr -d ' ')

Jeśli jednak mamy znaki kontrolne, może się to zepsuć. Tak więc, zgodnie z sugestią Kasperda, moglibyśmy mieć wokół niego podwójne cudzysłowy. Więc,

text="$(echo "$text" | tr -d ' ')"

będzie lepsza wersja.

Ramesh
źródło
Wspaniale! Byłem bardzo blisko. Jako noob cieszę się, że podążyłem we właściwym kierunku! Dziękuję również za szybką odpowiedź, jak tylko zaczekam 8 minut, prześlę to jako odpowiedź!
user3347022,
@ user3347022, nie ma za co :)
Ramesh
1
To się zepsuje, jeśli $textzawiera znaki kontrolne, które zostałyby zinterpretowane przez powłokę. Lepiej wstaw tam podwójne cudzysłowy:text="$(echo "$text" | tr -d ' ')"
kasperd
@kasperd, dziękuję, że o tym wspomniałeś. Uwzględniłem twoją sugestię.
Ramesh
4
$ sed 's. ..g' <<< $text
namewithspace
Steven Penny
źródło
2

szczególny przypadek, gdy potrzebujesz zmiennej o numerze:

sh:

typeset -i A=B #or
typeset -i A="   23232"

ksh:

typeset -n A=B #or
typeset -n A="   23232"
Tagar
źródło