Manipulowanie ciągiem szarpania rur


9

Przeczytałem kilka innych pytań dotyczących manipulacji ciągami bashowymi, ale wydaje się, że są to wyspecjalizowane aplikacje.

Zasadniczo, czy jest sposób, aby zrobić poniższe prostsze?

zamiast

$ string='hello world'; string2="${string// /_}"; echo "${string2^^}"
HELLO_WORLD

coś jak

$ echo 'hello world' | $"{-// /_}" | "${ -^^}"
HELLO_WORLD

Edytuj Jestem zainteresowany utrzymywaniem manipulacji bash, jeśli to możliwe, aby utrzymać prędkość (w przeciwieństwie do sed / awk, które mają tendencję do znacznego spowalniania moich skryptów)

Edycja2: @jimmij

Podoba mi się drugi przykład i doprowadziłem mnie do stworzenia funkcji.

bash_m() { { read x; echo "${x// /_}"; } | { read x; echo "${x^^}"; }; }
echo hello world | bash_m
HELLO_WORLD

1
jak myślisz, dlaczego sed / awk byłby powolny w tym celu? Są tak szybcy, jak przybywają.
mkc

1
@Ketan Sed i awk są osobnymi procesami, więc nigdy nie mogą być szybkie, jak bash może zrobić natywnie bez uruchamiania osobnego procesu. Zwykle różnica ta jest prawie niezauważalna, ale tam gdzie wydajność ma znaczenie w skryptach powłoki, zwykle występuje pewna pętla lub obliczenia są powtarzane bardzo wiele razy, a odradzanie tysięcy procesów będzie zauważalnie wolniejsze niż wykonywanie prostej operacji na łańcuchach w nash.
jw013,

2
@ jw013 Odnosi się to do krótkich łańcuchów jako „witaj świecie” z pytania, ale jeśli łańcuch jest bardzo długi, powiedz w trinstrukcji, to odwrotnie, ponieważ czas odradzania procesów jest pomijalny w porównaniu do czasu manipulacji łańcuchem, dla którego sedi awksą oddani. Jeśli ciąg znaków jest bardzo długi, powiedzmy całą instrukcję bash, wtedy bash może po prostu odmówić kontynuowania, z powodu pewnych wewnętrznych ograniczeń.
jimmij

2
@ jw013 jestem twierdząc kod manipulacji ciąg bash jest mniej wydajne następnie dedykowane narzędzia jak sed, awk, trlub podobnych. Spójrz na odpowiedź gena2x, którą edytowałem jakiś czas temu, dodając dokładnie tę informację: unix.stackexchange.com/questions/162221/ ... możesz porównać ją z odpowiedzią Terdona na to samo pytanie, w którym daje on czas na krótkie łańcuchy, w których spawnowanie procesu zajmuje najwięcej czasu. Możesz to przetestować samodzielnie i opublikować wynik.
jimmij

1
@Miati Dlaczego uważasz, że ten dodatek read x; echo $xjest lepszy dla wydajności? Składnia nie wygląda na krótszą ani bardziej przejrzystą. x=${x// /_}; x=${x^^}jest o wiele bardziej zwięzłym sposobem robienia tego samego {read x; echo ${x.... Jeśli chodzi o wydajność, @jimmij wskazał, że tr/ sedbędzie szybszy niż bash, przy równej liczbie rozwidleń. Użycie rury zawsze powoduje dodatkowy proces, więc argument o zapisaniu widelca nie ma już zastosowania. Tak więc, jeśli używasz potoków, po prostu użyj sed/ tritd. Jeśli możesz to zrobić w bash, zrób to i pomiń ten read x; echo $xnonsens.
jw013

Odpowiedzi:


9

Co powiedział Jimmij. Jego ostatnim przykładem jest najbliżej tego, co próbujesz wyrazić mimochodem.

Oto wariant tego tematu:

echo 'hello world'|echo $(read s;s=${s^^};echo ${s// /_})

Byłbym skłonny do użycia tr, ponieważ jest dość szybki.

echo 'hello world'|tr ' [:lower:]' '_[:upper:]'

Przypuszczam, że szkoda, że ​​bash nie pozwala na zagnieżdżanie parametrów; OTOH, użycie takich zagnieżdżonych wyrażeń może z łatwością prowadzić do kodu, który jest bolesny do odczytania. Jeśli naprawdę nie potrzebujesz rzeczy, aby działać tak szybko, jak to możliwe, lepiej napisać kod, który jest łatwy do odczytania, zrozumienia i utrzymania, niż sprytnie wyglądający kod, który jest PITA do debugowania. A jeśli naprawdę robić rzeczy muszą być wykonywane z maksymalną prędkością należy używać skompilowany kod, nie skrypt.


7

Nie można w ten sposób przekazywać rozszerzeń parametrów. Kiedy mówisz o xużywaniu $symbolu w "${x}"formie, to musi to być prawdziwa nazwa zmiennej, a nie standardowe wejście, przynajmniej nie w bash. W zshmożna wykonać zagnieżdżone podstawienia parametrów w następujący sposób:

$ x=''hello world'
$ echo ${${x// /_}:u}
HELLO_WORLD

(uwaga: :ujest dla zshtego samego co ^^dla bash)

Zagnieżdżanie w bashu nie jest możliwe i myślę, że to, co napisałeś, jest najlepsze, co możesz dostać, ale jeśli z jakiegoś dziwnego powodu musisz włączyć rury do równania, możesz spróbować tego:

$ echo 'hello world' | { read x; echo "${x// /_}"; } | { read y; echo "${y^^}"; }
HELLO_WORLD

1
Biorąc pod uwagę naszą ostatnią rozmowę na temat tego, jak tr/ sedsą szybsze niż bashpodczas przetwarzania ciągów, i biorąc pod uwagę, w jaki sposób używasz potoków do przekazywania ciągów przez standardowe we / wy, widzę dosłownie zero punktu, aby wykonywać te operacje w bashu w przeciwieństwie do tr/ sed. Dlaczego ktoś miałby | { read x; echo $x... }w przeciwieństwie do | sedczegoś, co robi to samo?
jw013

1
@ jw013 szczerze mówiąc nie widzę żadnego sensu. To tylko przykład, aby mocno angażować rur do problemu, bo PO wyraźnie poprosił o nich i nie chcą korzystać z programów zewnętrznych (zarówno echoi readsą bash Zabudowy, więc w zasadzie trochę szybciej). Jak już napisałem w odpowiedzi, progresywne manipulowanie parametrami, jakie OP ma w pytaniu, jest najlepsze, co moim zdaniem można uzyskać do tego zadania w bash. W każdym razie problem jest raczej akademicki.
jimmij
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.