O tak; wyjaśnienie: nie wszystkie wersje seda rozumieją \tw części zamiennej wyrażenia (rozpoznano ją \tw części pasującej do wzorca)
John Weldon
3
awwwwwwwwwwwwwwwwwww, ok, to całkiem interesujące. I dziwne. Dlaczego miałbyś go rozpoznać w jednym miejscu, a nie w drugim ...?
sixtyfootersdude
2
Wywołane ze skryptu, to nie zadziała: karty będą ignorowane przez sh. Na przykład poniższy kod ze skryptu powłoki doda $ TEXT_TO_ADD bez poprzedzania go tabelą: sed "$ {LINE} a \\ $ TEXT_TO_ADD" $ FILE.
Byłeś na dobrej drodze z $'string'wyjaśnieniem, ale brakuje ci. W rzeczywistości podejrzewam, ze względu na wyjątkowo niewygodne użycie, które prawdopodobnie masz niepełne zrozumienie (jak większość z nas robi z bashem). Zobacz moje wyjaśnienie poniżej: stackoverflow.com/a/43190120/117471
Bruno Bronosky
1
Pamiętaj, że BASH nie będzie rozszerzał zmiennych, tak jak $TABwewnątrz pojedynczych cudzysłowów, więc będziesz musiał używać go w podwójnych cudzysłowach.
nealmcb
Uważaj na używanie *podwójnych cudzysłowów ... będzie to traktowane jako glob, a nie jako wyrażenie regularne, które zamierzasz.
levigroker
28
@sedit był na właściwej ścieżce, ale definiowanie zmiennej jest trochę niewygodne.
Rozwiązanie (specyficzne dla bash)
Sposobem na zrobienie tego w bash jest umieszczenie znaku dolara przed łańcuchem w pojedynczym cudzysłowie.
$ echo -e '1\n2\n3'123
$ echo -e '1\n2\n3'| sed 's/.*/\t&/g'
t1
t2
t3
$ echo -e '1\n2\n3'| sed $'s/.*/\t&/g'123
Jeśli twój ciąg musi zawierać rozwinięcie zmiennych, możesz umieścić łańcuchy w cudzysłowie w następujący sposób:
$ timestamp=$(date +%s)
$ echo -e '1\n2\n3'| sed "s/.*/$timestamp"$'\t&/g'149123795811491237958214912379583
Słowa w postaci $ 'string' są traktowane specjalnie. Słowo jest interpretowane jako łańcuch , a znaki ze znakami ucieczki odwrotnym ukośnikiem są zastępowane zgodnie ze standardem ANSI C. Sekwencje ucieczki z ukośnikiem odwrotnym, jeśli są obecne, są dekodowane ...
Rozszerzony wynik jest podawany w apostrofy, tak jakby znak dolara nie był obecny.
Rozwiązanie (jeśli musisz unikać bash)
Osobiście uważam, że większość wysiłków mających na celu uniknięcie basha jest głupia, ponieważ unikanie bashizmu NIE * sprawia, że kod jest przenośny. (Twój kod będzie mniej kruchy, jeśli go uderzysz, bash -euniż jeśli spróbujesz uniknąć basha i użyjesz sh[chyba że jesteś absolutnym ninja POSIX].) Ale zamiast dyskutować na ten temat religijnie, dam ci tylko NAJLEPSZE * odpowiedź.
$ echo -e '1\n2\n3'| sed "s/.*/$(printf '\t')&/g"123
* Najlepsza odpowiedź? Tak, ponieważ jednym z przykładów tego, co większość skryptów powłoki anty-bash zrobiłaby źle w swoim kodzie, jest użycie echo '\t'tak, jak w odpowiedzi @ robrecord . To zadziała dla echa GNU, ale nie echa BSD. Wyjaśnia to The Open Group na http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 I to jest przykład dlaczego próby uniknięcia bashizmów zwykle zawodzą.
To zabawne, że używasz specyficznej funkcji "GNU echo" (interpretując \ t jako znak tabulacji) do rozwiązania błędu specyficznego dla "BSD sed" (interpretując \ t jako 2 oddzielne znaki). Przypuszczalnie, jeśli masz „GNU echo”, miałbyś także „GNU sed”. W takim przypadku nie musisz używać echa. W przypadku BSD echo wypisze echo '\t'2 oddzielne znaki. Przenośnym sposobem POSIX jest użycie printf '\t'. Dlatego mówię: nie próbuj przenosić swojego kodu, nie używając basha. To trudniejsze niż myślisz. Używanie bashjest najbardziej przenośną rzeczą, jaką większość z nas może zrobić.
Bruno Bronosky
3
Nie musisz używać sed do podstawiania, gdy w rzeczywistości chcesz po prostu wstawić tabulator przed linią. Zastępowanie w tym przypadku jest kosztowną operacją w porównaniu do zwykłego drukowania, zwłaszcza podczas pracy z dużymi plikami. Jest też łatwiejszy do odczytania, ponieważ nie zawiera wyrażenia regularnego.
sednie obsługuje \t, ani innych sekwencji ucieczki, jak \nw tym przypadku. Jedynym sposobem, w jaki udało mi się to zrobić, było wstawienie znaku tabulacji do skryptu za pomocąsed .
To powiedziawszy, możesz rozważyć użycie Perla lub Pythona. Oto krótki skrypt w Pythonie, który napisałem, i którego używam do wszystkich regexów strumieniowych:
Myślę, że inni wyjaśnić to odpowiednio do innych metod ( sed, AWK, itd.). Jednak moje bashodpowiedzi specyficzne (przetestowane na macOS High Sierra i CentOS 6/7) są dalej.
1) Jeśli OP chciałby użyć metody wyszukiwania i zamiany podobnej do tej, którą pierwotnie zaproponowali, sugerowałbym użycie perldo tego w następujący sposób. Uwagi: ukośniki odwrotne przed nawiasami dla wyrażenia regularnego nie powinny być konieczne, a ta linia kodu odzwierciedla, w jaki sposób $1lepiej jest używać niż \1z perloperatorem podstawienia (np. W dokumentacji Perl 5 ).
2) Jednak, jak wskazał ghostdog74 , ponieważ pożądaną operacją jest po prostu dodanie tabulatora na początku każdego wiersza przed zmianą pliku tmp na plik wejściowy / docelowy ( $filename), polecam perlponownie, ale z następującą modyfikacją (s):
3) Oczywiście plik tmp jest zbędny , więc lepiej po prostu zrobić wszystko `` na miejscu '' (dodając -iflagę) i uprościć wszystko do bardziej eleganckiej jednowierszowej
Odpowiedzi:
Nie wszystkie wersje
sed
rozumieją\t
. Po prostu wstaw zamiast tego dosłowną tabulator (naciśnij Ctrl- Va następnie Tab).źródło
\t
w części zamiennej wyrażenia (rozpoznano ją\t
w części pasującej do wzorca)Używając Bash możesz wstawić znak TAB programowo, tak jak poniżej:
źródło
$'string'
wyjaśnieniem, ale brakuje ci. W rzeczywistości podejrzewam, ze względu na wyjątkowo niewygodne użycie, które prawdopodobnie masz niepełne zrozumienie (jak większość z nas robi z bashem). Zobacz moje wyjaśnienie poniżej: stackoverflow.com/a/43190120/117471$TAB
wewnątrz pojedynczych cudzysłowów, więc będziesz musiał używać go w podwójnych cudzysłowach.*
podwójnych cudzysłowów ... będzie to traktowane jako glob, a nie jako wyrażenie regularne, które zamierzasz.@sedit był na właściwej ścieżce, ale definiowanie zmiennej jest trochę niewygodne.
Rozwiązanie (specyficzne dla bash)
Sposobem na zrobienie tego w bash jest umieszczenie znaku dolara przed łańcuchem w pojedynczym cudzysłowie.
Jeśli twój ciąg musi zawierać rozwinięcie zmiennych, możesz umieścić łańcuchy w cudzysłowie w następujący sposób:
Wyjaśnienie
W bash
$'string'
powoduje "rozszerzenie ANSI-C". I to jest to, co większość z nas spodziewać, gdy używamy takich rzeczy\t
,\r
,\n
, itd. Od: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-QuotingRozwiązanie (jeśli musisz unikać bash)
Osobiście uważam, że większość wysiłków mających na celu uniknięcie basha jest głupia, ponieważ unikanie bashizmu NIE * sprawia, że kod jest przenośny. (Twój kod będzie mniej kruchy, jeśli go uderzysz,
bash -eu
niż jeśli spróbujesz uniknąć basha i użyjeszsh
[chyba że jesteś absolutnym ninja POSIX].) Ale zamiast dyskutować na ten temat religijnie, dam ci tylko NAJLEPSZE * odpowiedź.* Najlepsza odpowiedź? Tak, ponieważ jednym z przykładów tego, co większość skryptów powłoki anty-bash zrobiłaby źle w swoim kodzie, jest użycie
echo '\t'
tak, jak w odpowiedzi @ robrecord . To zadziała dla echa GNU, ale nie echa BSD. Wyjaśnia to The Open Group na http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 I to jest przykład dlaczego próby uniknięcia bashizmów zwykle zawodzą.źródło
Użyłem czegoś takiego z powłoką Bash na Ubuntu 12.04 (LTS):
Aby dołączyć nową linię z tabulatorem, druga po dopasowaniu pierwszej :
Aby wymienić pierwsze z zakładki, po drugie :
źródło
\\t
a nie\t
.Posługiwać się
$(echo '\t')
. Będziesz potrzebować cytatów wokół wzoru.Na przykład. Aby usunąć kartę:
źródło
echo '\t'
2 oddzielne znaki. Przenośnym sposobem POSIX jest użycieprintf '\t'
. Dlatego mówię: nie próbuj przenosić swojego kodu, nie używając basha. To trudniejsze niż myślisz. Używaniebash
jest najbardziej przenośną rzeczą, jaką większość z nas może zrobić.Nie musisz używać
sed
do podstawiania, gdy w rzeczywistości chcesz po prostu wstawić tabulator przed linią. Zastępowanie w tym przypadku jest kosztowną operacją w porównaniu do zwykłego drukowania, zwłaszcza podczas pracy z dużymi plikami. Jest też łatwiejszy do odczytania, ponieważ nie zawiera wyrażenia regularnego.np. używając awk
źródło
Użyłem tego na Macu:
Użyłem tego linku w celach informacyjnych
źródło
sed
nie obsługuje\t
, ani innych sekwencji ucieczki, jak\n
w tym przypadku. Jedynym sposobem, w jaki udało mi się to zrobić, było wstawienie znaku tabulacji do skryptu za pomocąsed
.To powiedziawszy, możesz rozważyć użycie Perla lub Pythona. Oto krótki skrypt w Pythonie, który napisałem, i którego używam do wszystkich regexów strumieniowych:
źródło
Zamiast seda z BSD używam perla:
źródło
Myślę, że inni wyjaśnić to odpowiednio do innych metod (
sed
,AWK
, itd.). Jednak mojebash
odpowiedzi specyficzne (przetestowane na macOS High Sierra i CentOS 6/7) są dalej.1) Jeśli OP chciałby użyć metody wyszukiwania i zamiany podobnej do tej, którą pierwotnie zaproponowali, sugerowałbym użycie
perl
do tego w następujący sposób. Uwagi: ukośniki odwrotne przed nawiasami dla wyrażenia regularnego nie powinny być konieczne, a ta linia kodu odzwierciedla, w jaki sposób$1
lepiej jest używać niż\1
zperl
operatorem podstawienia (np. W dokumentacji Perl 5 ).2) Jednak, jak wskazał ghostdog74 , ponieważ pożądaną operacją jest po prostu dodanie tabulatora na początku każdego wiersza przed zmianą pliku tmp na plik wejściowy / docelowy (
$filename
), polecamperl
ponownie, ale z następującą modyfikacją (s):3) Oczywiście plik tmp jest zbędny , więc lepiej po prostu zrobić wszystko `` na miejscu '' (dodając
-i
flagę) i uprościć wszystko do bardziej eleganckiej jednowierszowejźródło