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.

Brian Leishman
źródło

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 .

Brian Clapper
źródło
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.

aioobe
źródło
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'
Gilles „SO- przestań być zły”
źródło
24

Spróbuj tego

 echo "hello world" | sed 's/ /./g' 
Obrabować
źródło
6

Użyj podstawienia parametru:

string=${string// /.}
Fritz G. Mehner
źródło
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'
dsrdakota
źródło
2
Istnieje już dwuletnia odpowiedź, która rozwiązuje problem sed. Cytaty są nieistotne.
chepner