Istnieje wiele sposobów zamiany znaków w zmiennej.
Najkrótsza droga, jaką się dowiedziałem, to tr
:
OUTPUT=a\'b\"c\`d_123and_a_lot_more
OUTPUT=$(echo "$OUTPUT"|tr -d "'\`\"")
echo $OUTPUT
Czy jest szybszy sposób? I jest to bezpieczne dla cytowanie cytatów jak '
, "
i `sama?
tr
. PEH BASH jest dobry, ale w tym przypadku tr jest znacznie szybszy. np.echo "$OUTPUT" | tr -dc '[[:alpha:]]'
ponieważ chcesz mieć tylko alfanumeryczneecho "$OUTPUT"
. Albo lepiej:printf "%s\n" "$OUTPUT"
. (Co się stanie, kiedyOUTPUT="-n"
?)Odpowiedzi:
Zobaczmy. Najkrótsze, jakie mogę wymyślić, to ulepszenie twojego
tr
rozwiązania:Inne alternatywy obejmują wspomniane już podstawienie zmiennych, które może być krótsze niż dotychczas pokazane:
I
sed
oczywiście jest to dłuższe pod względem postaci:Nie jestem pewien, czy masz na myśli najkrótszą długość lub czas. Jeśli chodzi o długość, te dwa są tak krótkie, jak to możliwe (lub tak czy inaczej mogę je zdobyć), jeśli chodzi o usuwanie tych konkretnych postaci. Który jest najszybszy? Przetestowałem, ustawiając
OUTPUT
zmienną na wartość z przykładu, ale powtórzyłem kilkadziesiąt razy:Jak widać,
tr
jest zdecydowanie najszybszy, a tuż za nimsed
. Wygląda na to, że używanieecho
jest nieco szybsze niż używanie<<<
:Ponieważ różnica jest niewielka, powyższe testy przeprowadziłem 10 razy dla każdego z nich i okazuje się, że najszybszy jest rzeczywiście ten, od którego musiałeś zacząć:
Zmienia się to jednak, gdy weźmie się pod uwagę narzut związany z przypisywaniem zmiennej, tutaj użycie
tr
jest nieco wolniejsze niż zwykła zamiana:Podsumowując, gdy chcesz po prostu wyświetlić wyniki, użyj,
tr
ale jeśli chcesz ponownie przypisać do zmiennej, korzystanie z funkcji manipulacji ciągiem powłoki jest szybsze, ponieważ pozwalają uniknąć nakładania się na osobną podpowłokę.źródło
OUTPUT
, będziesz musiał wziąć pod uwagę narzuty zastępcze poleceń związane ztr
sed
OUTPUT="${OUTPUT//[`\"\']/}"
nie obejmuje zastępowania poleceńMożesz użyć podstawienia zmiennej :
Użyj tej składni:
${parameter//pattern/string}
aby zastąpić wszystkie wystąpienia wzorca łańcuchem.źródło
echo ${OUTPUT//[`\"\']/x}
dajeaxbxcxa
W bash lub zsh jest to:
Zauważ, że
${VAR//PATTERN/}
usuwa wszystkie wystąpienia wzorca. Aby uzyskać więcej informacji , rozszerzenie parametru bashTo rozwiązanie powinno być najszybsze w przypadku krótkich ciągów, ponieważ nie wymaga uruchamiania żadnych programów zewnętrznych. Jednak w przypadku bardzo długich ciągów jest odwrotnie - lepiej jest używać dedykowanego narzędzia do operacji tekstowych, na przykład:
źródło
tr
jest szybszy. Regeksy i globusy są drogie i chociaż nie ma tutaj zewnętrznego programu, bash zawsze będzie wolniejszy niż coś w tym rodzajutr
.tr
wygrywa (zobacz moją odpowiedź). Zgadzam się, że będzie to zależeć od wielu czynników, ale właśnie dlatego nie można stwierdzić, który z nich wygra, nie testując go.Jeśli przypadkowo próbujesz poradzić sobie z cytatami dotyczącymi ponownego użycia powłoki, możesz to zrobić bez usuwania ich, a to również jest bardzo proste:
Ta funkcja powłoki cytuje każdą tablicę arg, którą jej podajesz, i zwiększa jej wynik na iterowalny argument.
Oto kilka argumentów:
WYNIK
To wyjście, z
dash
którego typowo bezpieczne cytaty zawierają pojedyncze cytaty'"'"'
.bash
zrobiłby'\''
.Zastąpienie wyboru pojedynczych bajtów niepustych białych znakami o wartości innej niż null innym pojedynczym bajtem można prawdopodobnie zrobić najszybciej w dowolnej powłoce POSIX za pomocą
$IFS
i$*
.WYNIK
Tam właśnie
printf
to widzę, ale oczywiście, gdybym to zrobił:... zamiast
printf
polecenia$var
„s wartość byłaby co widać w tam wyjście.Kiedy
set -f
instruuję powłokę, aby nie globowała - w przypadku gdy łańcuch zawiera znaki, które można by interpretować jako wzorce globu. Robię to, ponieważ parser powłok rozszerza wzorce globu po dokonaniu podziału pól na zmienne. globbing może być ponownie włączony jakset +f
. Ogólnie rzecz biorąc - w skryptach - przydatne jest ustawienie huku w następujący sposób:A następnie, aby jawnie włączyć globowanie z
set +f
dowolną linią, której bym tego chciał.Podział pola następuje na podstawie znaków w
$IFS
.Istnieją dwa rodzaje
$IFS
wartości -$IFS
białe znaki i$IFS
inne znaki.$IFS
spacje (spacja, tabulator, nowa linia) pola rozdzielane są określane tak, aby następowały po nich sekwencje do pojedynczego pola (lub wcale, jeśli nie poprzedzają czegoś innego) - więc ...Ale wszystkie inne są określone, aby oceniać do jednego pola na wystąpienie - nie są obcinane.
Wszystkie rozszerzenia zmiennych są domyślnie
$IFS
ograniczonymi tablicami danych - są one podzielone na osobne pola zgodnie z$IFS
. Kiedy ty"
cytujesz jedną, zastępujesz tę właściwość tablicy i oceniasz ją jako pojedynczy ciąg.Więc kiedy to zrobię ...
Ustawiam tablicę argumentów powłoki na wiele
$IFS
rozdzielanych pól generowanych przez$var
rozszerzenie. Po rozwinięciu jego wartości składowe dla zawartych w nim znaków$IFS
są tracone - są one teraz tylko separatorami pól - są\0NUL
."$*"
- podobnie jak inne podwójnie cytowane rozwinięcia zmiennych - również zastępuje właściwości podziału pola na$IFS
. Ale dodatkowo zastępuje pierwszy bajt w$IFS
każdym rozdzielanym polu w"$@"
. Tak, ponieważ"
był pierwszy wartość$IFS
wszystkich kolejnych ograniczniki stać"
w"$*"
. I"
nie trzeba też być$IFS
przy podziale. Można zmieniać$IFS
poset -- $args
innej wartości w całości i jego nowy pierwszy bajt by następnie pokazać się na ograniczniki polowych w"$*"
. Co więcej, możesz całkowicie usunąć wszystkie ich ślady:WYNIK
źródło
tr
w jakiejkolwiek powłoki, ale różnica jest niepewna wbash
dla${var//$c/$newc/}
sprawy. Spodziewam się, że nawet w takim przypadku będzie to nieco szybsze, ale zwykle nie przejmuję się tym, ponieważ do tych rzeczy zawsze używamdash
- co jest szybsze o rząd wielkości pod każdym względem. Trudno to porównać.bash
działaniu -time (IFS=\"\'`; set -- $var; printf %s "$*")
itime (var=${var//\'`/\"/})
oba dają0.0000s
wyniki dla wszystkich pól. Czy robię coś złego, myślisz? Tam powinien być odwrotny ukośnik przed odwrotnym cytatem, ale nie wiem, jak wstawić odwrotny cytat w polu kodu komentarza.