Zamień jedną postać na drugą w Bash


223

Muszę być w stanie zrobić to zastąpić spację ( ) kropką ( .) w ciągu w bash.

Myślę, że byłoby to dość proste, ale jestem nowy, więc nie mogę wymyślić, jak zmodyfikować podobny przykład dla tego zastosowania.

Odpowiedzi:


390

Użyj wbudowanej zamiany łańcucha powłoki. Przykład:

foo="  "

# replace first blank only
bar=${foo/ /.}

# replace all blanks
bar=${foo// /.}

Więcej informacji można znaleźć na stronie http://tldp.org/LDP/abs/html/string-manipulation.html .


1
Chociaż to rozwiązanie jest dobre, gdy mamy do czynienia z krótkimi łańcuchami (chyba zwykły przypadek), można wybrać trdłuższe ciągi. W moim systemie trprzewyższa bash zaczynając od ciągów zawierających więcej niż 1000znaki. Wydaje się, że złożoność czasu bash jest gorsza niż liniowa. Mały test: x="$(tr -dc 'a-z \n' </dev/urandom | head -c1M)"; time y="$(tr ' ' \\- <<< "$x")"; time z="${x// /-}". Przy długości łańcucha 1M (= 2 ^ 20) trwziął 0.04si bash 5.0.11 wziął 17s. Z 2M trwziął 0.07s(oczekiwany), ale bash wziął 69s(4 razy więcej na dwa razy długość łańcucha).
Socowi

@Socowi Gra z 1Mb przechowywanym w zmiennej nie jest tak naprawdę normalna! Do ponad 10 KB, bash wydaje się być szybszy niż rozwiązywanie zadań tr! ... W zależności od dostępnej pamięci i zasobów sprzętowych ... Ale masz rację !: W zależności od rodzaju zadania, dedykowane narzędzia pozostają wydajniejsze!
F. Hauri,

Aby znaleźć znaki specjalne, takie jak znak nowej linii, wyszukaj$'\n'
user2561747,

75

Możesz użyć trtakiego:

tr " " .

Przykład:

# echo "hello world" | tr " " .
hello.world

Od man tr:

OPIS
     Przetłumacz, ściśnij i / lub usuń znaki ze standardowego wejścia, pisząc na standardowe wyjście.


Chociaż działa to na zadane pytanie, jest mniej ogólne niż zaakceptowana odpowiedź (która działa na zastępowanie znaków, a także dowolne ciągi znaków), a także obejmuje i zewnętrzne polecenia.
Dan Dascalescu

2
Z drugiej strony działa na pliku 2 GB bez ładowania całej rzeczy do pamięci.
aioobe

Pytanie dotyczyło „ciągu w bash”, a nie dużych plików.
Dan Dascalescu

52

W bash możesz wykonać zamianę wzoru w ciągu za pomocą ${VARIABLE//PATTERN/REPLACEMENT}konstrukcji. Używaj tylko /i nie //zastępuj tylko pierwszego wystąpienia. Wzorzec jest wzorem wieloznacznym, podobnie jak globusy plików.

string='foo bar qux'
one="${string/ /.}"     # sets one to 'foo.bar qux'
all="${string// /.}"    # sets all to 'foo.bar.qux'



4

Wypróbuj to dla ścieżek:

echo \"hello world\"|sed 's/ /+/g'|sed 's/+/\/g'|sed 's/\"//g'

Zastępuje spację wewnątrz ciągu podwójnego cudzysłowu znakiem +sing, następnie zastępuje +znak odwrotnym ukośnikiem, a następnie usuwa / zamienia cudzysłowy.

Musiałem to wykorzystać, aby zastąpić spacje na jednej ze ścieżek w Cygwin.

echo \"$(cygpath -u $JAVA_HOME)\"|sed 's/ /+/g'|sed 's/+/\\/g'|sed 's/\"//g'

2
Istnieje już dwuletnia odpowiedź, która rozwiązuje problem sed. Cytaty są nieistotne.
chepner
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.