Mam skrypt powłoki z tym kodem:
var=`hg st -R "$path"`
if [ -n "$var" ]; then
echo $var
fi
Ale kod warunkowy zawsze wykonuje się, ponieważ hg st
zawsze drukuje co najmniej jeden znak nowej linii.
- Czy istnieje prosty sposób na usunięcie białych znaków
$var
(jaktrim()
w PHP )?
lub
- Czy istnieje standardowy sposób radzenia sobie z tym problemem?
Mógłbym użyć sed lub AWK , ale chciałbym pomyśleć, że istnieje bardziej eleganckie rozwiązanie tego problemu.
$ var=$(echo)
$ [ -n $var ]; echo $? #undesired test return
0
$ [[ -n $var ]]; echo $?
1
echo " This is a string of char " | xargs
. Jeśli jednak mają jeden cytat w tekście można wykonać następujące czynności:echo " This i's a string of char " | xargs -0
. Zauważ, że wspominam o najnowszym xargs (4.6.0)test=`echo`; if [ -n "$test" ]; then echo "Not empty"; fi
, ale to zrobitest=`echo "a"`; if [ -n "$test" ]; then echo "Not empty"; fi
- więc na końcu musi być coś więcej niż tylko nowa linia.echo $A | sed -r 's/( )+//g'
;Odpowiedzi:
Zdefiniujmy zmienną zawierającą początkowe, końcowe i pośrednie białe znaki:
Jak usunąć wszystkie białe znaki (oznaczone przez
[:space:]
intr
):Jak usunąć tylko wiodące białe znaki:
Jak usunąć tylko końcowe białe znaki:
Jak usunąć zarówno początkowe, jak i końcowe spacje - połącz łańcuchy
sed
s:Alternatywnie, jeśli bash obsługuje tę funkcję, można wymienić
echo -e "${FOO}" | sed ...
zesed ... <<<${FOO}
jak tak (za końcowe białe znaki):źródło
tr
ised
polecenia z[[:space:]]
. Należy pamiętać, żesed
podejście będzie działać tylko w przypadku wprowadzania jednowierszowego . Podejścia, które działają z wejściem wieloliniowym, a także wykorzystują wbudowane funkcje bash, zobacz odpowiedzi @bashfu i @GuruM. Uogólniona, wbudowana wersja rozwiązania @Nicholas Sushkin wyglądałaby następująco:trimmed=$([[ " test test test " =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]; echo -n "${BASH_REMATCH[1]}")
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"
do twojego~/.profile
pozwala ci używaćecho $SOMEVAR | trim
icat somefile | trim
.sed
rozwiązanie, które wykorzystuje tylko jeden wyraz zamiast dwóch:sed -r 's/^\s*(\S+(\s+\S+)*)\s*$/\1/'
. Przycina wiodące i końcowe białe znaki oraz przechwytuje sekwencje znaków innych niż białe znaki w środku. Cieszyć się!|
tak aby zachować je jako jedno wyrażenie, a nie kilka.Prosta odpowiedź to:
Xargs wykona dla Ciebie przycinanie. To jedno polecenie / program, bez parametrów, zwraca przycięty ciąg znaków, to proste!
Uwaga: to nie usuwa wszystkich wewnętrznych spacji, więc
"foo bar"
pozostaje takie samo; NIE staje się"foobar"
. Jednak wiele spacji zostanie skondensowanych do pojedynczych spacji, więc"foo bar"
stanie się"foo bar"
. Ponadto nie usuwa znaków końca linii.źródło
xargs echo
to, żeby mówić o tym, co robię, ale xargs samo w sobie domyślnie używa echa.sed 's/ *$//'
jako alternatywę. Możesz zobaczyćxargs
nową linię w ten sposób:echo -n "hey thiss " | xargs | hexdump
zauważysz,0a73
żea
jest to nowa linia. Jeśli zrobisz to samo zsed
:echo -n "hey thiss " | sed 's/ *$//' | hexdump
zobaczysz0073
, nie ma nowej linii.a<space><space>b
wa<space>b
. 2. Co więcej: zamieni sięa"b"c'd'e
wabcde
. 3. Co więcej: zawiedziea"b
, itp.Istnieje rozwiązanie wykorzystujące tylko wbudowane Bash zwane symbolami wieloznacznymi :
Oto to samo zawinięte w funkcję:
Podajesz ciąg do przycięcia w formie cytowanej. na przykład:
Zaletą tego rozwiązania jest to, że będzie ono działać z dowolną powłoką zgodną z POSIX.
Odniesienie
źródło
s=" 1 2 3 "; echo \""${s%1 2 3 }"\"
Przycinałby wszystko od końca, zwracając prowadzenie" "
. Subbing1 2 3
z[![:space:]]*
mówi mu, aby „znalazł pierwszą postać niebędącą spacją, a następnie ją przerobił i wszystko po”. Użycie%%
zamiast%
powoduje, że operacja przycinania od końca jest zachłanna. Jest to zagnieżdżone w niechcianym przycinaniu od początku, więc w efekcie przycinasz" "
od początku. Następnie zamień%, # i * na spacje końcowe. Bam!/bin/sh
(tylko z/usr/xpg4/bin/sh
, ale nie to będzie używane ze zwykłymi skryptami sh).${var%%[![:space:]]*}
mówi „usuń zvar
jego najdłuższego podłańcucha, który zaczyna się od znaku spacji”. Oznacza to, że masz tylko wiodące miejsca, które następnie usuwasz${var#..
. Następująca linia (końcowa) jest odwrotna.awk
,sed
,tr
,xargs
) jedynie przyciąć spacji z pojedynczego łańcucha jest całkowicie niepoczytalny - szczególnie gdy większość powłok (w tym bash) już zapewniają natywną ciąg munging zaplecze out-of-the-box.Bash ma funkcję zwaną rozszerzaniem parametrów , która między innymi umożliwia zamianę ciągów w oparciu o tak zwane wzorce (wzorce przypominają wyrażenia regularne, ale istnieją podstawowe różnice i ograniczenia). [oryginalny wiersz flussence: Bash ma wyrażenia regularne, ale są dobrze ukryte:]
Poniżej pokazano, jak usunąć całą spację (nawet z wnętrza) ze zmiennej wartości.
źródło
${var/ /}
usuwa pierwszy znak spacji.${var// /}
usuwa wszystkie znaki spacji. Nie ma możliwości przycięcia tylko wiodących i końcowych białych znaków za pomocą tylko tej konstrukcji.Aby usunąć wszystkie spacje od początku i końca ciągu (w tym znaki końca wiersza):
Spowoduje to również usunięcie duplikatów:
Tworzy: „ten ciąg ma wiele spacji”
źródło
echo -n
?echo " my string " | xargs
ma taką samą moc wyjściową.Usuń jedną przestrzeń wiodącą i jedną końcową
Na przykład:
Wynik:
Usuń wszystkie wiodące i końcowe spacje
Na przykład:
Wynik:
źródło
'hello world ', 'foo bar', 'both sides '
Z sekcji Przewodnik po Bash na temat globowania
Aby użyć extglob w rozszerzeniu parametru
Oto ta sama funkcjonalność zawarta w funkcji (UWAGA: Należy zacytować ciąg wejściowy przekazany do funkcji):
Stosowanie:
Jeśli zmienimy funkcję, aby była wykonywana w podpowłoce, nie musimy się martwić o sprawdzenie bieżącej opcji powłoki dla extglob, możemy po prostu ustawić ją bez wpływu na bieżącą powłokę. Upraszcza to ogromnie tę funkcję. Aktualizuję również parametry pozycyjne „na miejscu”, więc nawet nie potrzebuję zmiennej lokalnej
więc:
źródło
extglob
, używającshopt -p
: po prostu napiszlocal restore="$(shopt -p extglob)" ; shopt -s extglob
na początku swojej funkcji ieval "$restore"
na końcu (z wyjątkiem tego, że eval jest złe…).[[:space:]]
można ją zastąpić spacją:${var##+( )}
a także${var%%+( )}
pracować i są łatwiejsze do odczytania.Możesz przycinać po prostu za pomocą
echo
:źródło
foo
zawiera symbol wieloznaczny? np.foo=" I * have a wild card"
... niespodzianka! Ponadto łączy to kilka sąsiadujących ze sobą przestrzeni w jedną.Zawsze robiłem to z sedem
Jeśli istnieje bardziej eleganckie rozwiązanie, mam nadzieję, że ktoś je opublikuje.
źródło
sed
?sed -e 's/\s*$//'
. Objaśnienie: „s” oznacza wyszukiwanie, „\ s” oznacza całą białą spację, „*” oznacza zero lub wiele, „$” oznacza do końca wiersza, a „//” oznacza zastąpienie wszystkich dopasowań pustym łańcuchem .Możesz usunąć nowe linie za pomocą
tr
:źródło
Po włączeniu funkcji rozszerzonego dopasowania wzorca Bash (
shopt -s extglob
) możesz użyć tego:{trimmed##*( )}
aby usunąć dowolną liczbę wiodących spacji.
źródło
/bin/sh -o posix
też działa, ale jestem podejrzliwy.trimmed
? Czy jest to rzecz wbudowana czy zmienna, która jest przycinana?źródło
read
będzie przechowywana w zmiennej pod nazwą 1 $ skrócona wersja wartości $ {! 1}trim() { while [[ $# -gt 0 ]]; do read -rd '' $1 <<<"${!1}"; shift; done; }
read -rd '' str <<<"$str"
.Istnieje wiele odpowiedzi, ale nadal uważam, że mój właśnie napisany skrypt jest wart wspomnienia, ponieważ:
"$*"
łączy wiele argumentów za pomocą jednej spacji. jeśli chcesz przyciąć i wypisać tylko pierwszy argument, użyj"$1"
zamiast niegoScenariusz:
Stosowanie:
Wynik:
źródło
[\ \t]
[[:space:]]
Możesz użyć starej szkoły
tr
. Na przykład zwraca liczbę zmodyfikowanych plików w repozytorium git, bez białych znaków.źródło
To działało dla mnie:
Aby umieścić to w mniejszej liczbie wierszy dla tego samego wyniku:
źródło
${var##Pattern}
uzyskać więcej szczegółów. Ponadto ta strona wyjaśnia wzorce bash . Tak więc##
środki usuwają dany wzór z przodu, a%%
środki usuwają dany wzór z tyłu.+( )
Część jest wzorem, a to oznacza „jeden lub więcej występowanie miejsca”LUB
LUB
LUB
LUB
Opierając się na expr soulution moskita ...
LUB
źródło
Widziałem, że skrypty po prostu wykorzystują zmienne przypisanie do wykonania zadania:
Biała spacja jest automatycznie łączona i przycinana. Trzeba uważać na metaznaki powłoki (potencjalne ryzyko wstrzyknięcia).
Poleciłbym również zawsze podwójne cytowanie podstawień zmiennych w warunkach powłoki:
ponieważ coś takiego jak -o lub inna treść w zmiennej może zmienić twoje argumenty testowe.
źródło
$xyz
zecho
tym, że łączy się biała spacja, a nie przypisanie zmiennej. Aby zapisać przyciętą wartość w zmiennej w twoim przykładzie, musisz użyćxyz=$(echo -n $xyz)
. Również to podejście podlega potencjalnie niepożądanemu rozszerzaniu nazw ścieżek (globbing).xyz
zmiennej NIE jest przycinana.źródło
echo $(echo "1 2 3")
(z dwoma spacjami między 1, 2 i 3).Po prostu użyłbym sed:
a) Przykład użycia ciągu jednowierszowego
Wynik:
b) Przykład użycia ciągu wieloliniowego
Wynik:
c) Uwaga końcowa:
jeśli nie chcesz używać funkcji, w przypadku ciągu jednowierszowego możesz po prostu użyć polecenia „łatwiej zapamiętać”, takiego jak:
Przykład:
Wynik:
Używanie powyższego w ciągach wielowierszowych również będzie działać , ale pamiętaj, że spowoduje to również odcięcie końcowej / wiodącej wewnętrznej przestrzeni wielokrotnej, jak zauważył GuruM w komentarzach
Wynik:
Więc jeśli masz ochotę zachować te spacje, skorzystaj z funkcji na początku mojej odpowiedzi!
d) OBJAŚNIENIE składni sed „znajdź i zamień” na ciągi wielowierszowe używane wewnątrz wykończenia funkcji:
źródło
Oto funkcja trim (), która przycina i normalizuje białe znaki
I inny wariant wykorzystujący wyrażenia regularne.
źródło
*
znak w ciągu wejściowym rozwiń do wszystkich plików i folderów w bieżącym folderze roboczym. Na koniec, jeśli $ IFS jest ustawione na wartość inną niż domyślna, przycinanie może nie działać (choć łatwo temu zaradzić poprzez dodanielocal IFS=$' \t\n'
). Przycinanie jest ograniczone do następujących form białych znaków: spacji\t
i\n
znaków.if
linię z:if [[ "$trimmed" =~ ' '*([^ ]|[^ ].*[^ ])' '* ]]
. Wreszcie podejście to dotyczy tylko spacji, a nie innych form białych znaków (patrz mój następny komentarz).if
wiersz na:[[ "$trimmed" =~ [[:space:]]*([^[:space:]]|[^[:space:]].*[^[:space:]])[[:space:]]* ]]
Użyj AWK:
źródło
$stripped_version=
echo $ var | awk '{gsub (/ ^ + | + $ /, "")} 1' 'Przypisania ignorują wiodące i końcowe białe znaki i jako takie mogą być używane do przycinania:
źródło
echo "$var"
aby zobaczyć wartość ze spacjami.var=$(echo $var)
ale nie polecam. Preferowane są inne przedstawione tutaj rozwiązania.Nie ma to problemu z niechcianym globowaniem, ponadto wewnętrzna biała przestrzeń jest niezmodyfikowana (zakładając, że
$IFS
jest ustawiona na wartość domyślną, która jest' \t\n'
).Czyta do pierwszej nowej linii (i nie obejmuje jej) lub do końca łańcucha, w zależności od tego, co nastąpi wcześniej, i usuwa wszelką kombinację początkowej i końcowej spacji oraz
\t
znaków. Jeśli chcesz zachować wiele linii (a także rozdzielić początkowe i końcowe znaki nowej linii), użyjread -r -d '' var << eof
zamiast tego; zwróć jednak uwagę, że jeśli twoje dane wejściowe zawierają\neof
, zostaną odcięte tuż przed. (Inne formy białych znaków, a mianowicie\r
,\f
i nie\v
są usuwane, nawet jeśli dodasz je do $ IFS.)źródło
Aby usunąć spacje i tabulatory od lewej do pierwszej litery, wpisz:
cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-word.html
źródło
Spowoduje to usunięcie wszystkich białych znaków z łańcucha,
/
zastępuje pierwsze wystąpienie i//
wszystkie wystąpienia białych znaków w ciągu. To znaczy wszystkie białe spacje zostaną zastąpione przez - nicźródło
To najprostsza metoda, jaką widziałem. Używa tylko Bash, to tylko kilka wierszy, wyrażenie regularne jest proste i pasuje do wszystkich form białych znaków:
Oto przykładowy skrypt do przetestowania:
źródło
^[[:space:]]*(.*[^[:space:]])?[[:space:]]*$
Python ma funkcję,
strip()
która działa identycznie jak PHPtrim()
, więc możemy po prostu zrobić trochę wbudowanego Pythona, aby stworzyć łatwo zrozumiałe narzędzie do tego:Spowoduje to przycięcie początkowych i końcowych białych znaków (w tym znaków nowej linii).
źródło
źródło
Odkryłem, że muszę dodać trochę kodu z nieporządnego
sdiff
wyjścia, aby go wyczyścić:Usuwa to końcowe spacje i inne niewidzialne znaki.
źródło
Usuwanie spacji do jednej spacji:
źródło