Jak wydrukować ciągi oddzielone TAB w bash?


9

Próbuję wydrukować dwa ciągi znaków oddzielone TAB. Próbowałem:

echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar

Oba drukują:

foo     bar

Gdzie biała spacja między nimi wynosi w rzeczywistości 5 spacji (zgodnie z wyborem wyjścia za pomocą myszy w Putty).

Próbowałem również użyć CTRL + V i naciskając TAB podczas wpisywania polecenia, z tym samym rezultatem.

Jaki jest właściwy sposób na wymuszenie drukowania tabulatora jako tabulatora, dzięki czemu mogę wybrać wynik i skopiować go w inne miejsce, używając tabulatorów?

I drugie pytanie: dlaczego bash rozwija tabulatory w spacje?

Aktualizacja : Najwyraźniej jest to problem Putty: /superuser/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changing-them-to -przestrzenie



Dlaczego po prostu nie uciec? printf '%s\\t%s\n' foo bar
Valentin Bajrami,

@steeldriver Dzięki, to bardzo podobne do tego, czego potrzebuję, ale ostatecznie nie ma rozwiązania ...
Asu

1
@ Valentin That Output foo\tbar...
wjandrea

1
Pomimo tego, że już wiesz, że masz problem z terminalem: sam Bash interpretuje $'\t'jako tabulator. Możesz więc zawsze łączyć takie ciągi znaków - na przykład jako zadanie: v='This is'$'\t''a test'I drukować dosłownie, np.printf '%s' "$v"
rexkogitans

Odpowiedzi:


9

Jak powiedział ilkkachu, nie jest to problem z bash, ale z emulatorem terminala, który konwertuje tabulatory na spacje na wyjściu.

Sprawdzanie różnych terminali, putty, xterm i konsoli zamienia tabulatory na spacje, podczas gdy urxvt i gnome-terminal nie. Kolejnym rozwiązaniem jest zmiana terminali.


3
Może to również zostać wykonane przez sterownik tty po uruchomieniu stty tab3.
Stéphane Chazelas,

14

odstęp między nimi wynosi w rzeczywistości 5 spacji.

Nie, nie jest. Brak danych wyjściowych echolub printf.

$ echo -e 'foo\tbar' | od -c
0000000   f   o   o  \t   b   a   r  \n
0000010

Jaki jest właściwy sposób na wymuszenie drukowania tabulatora jako tabulatora, dzięki czemu mogę wybrać wynik i skopiować go w inne miejsce, używając tabulatorów?

To inny problem. Nie chodzi o powłokę, ale emulator terminala, który konwertuje tabulatory na spacje na wyjściu. Wielu, ale nie wszyscy to robią.

Może być łatwiej przekierować dane wyjściowe z tabulatorami do pliku i skopiować je stamtąd lub użyć unexpandna wyjściu do konwersji spacji na tabulatory. (Chociaż nie może również wiedzieć, od czego na początku były białe znaki, i jeśli to możliwe, przekonwertuje je na tabulatory). To oczywiście zależeć będzie od tego, co dokładnie trzeba zrobić z wydrukiem.


Miałem na myśli to, że gdy próbuję wybrać wyjście, jest ono traktowane jako 5 spacji. Dzięki za polecenie „od -c” w celu zweryfikowania zawartości danych wyjściowych polecenia.
Asu,

1
@Asu Myślę, że on to rozumie. Jego rozwiązaniem jest uzyskanie danych wyjściowych za pomocą innych środków, ponieważ emulator terminala nie gwarantuje pozostawienia zakładek jako zakładek po wybraniu ich w oknie. Jednak właśnie sprawdziłem i podczas gdy putty, xterm i konsola konwertują tabulatory na spacje, urxvt i gnome-terminal nie. Kolejnym rozwiązaniem jest zmiana terminali.
JoL

@JoL Tak, do takiego wniosku doszedłem minutę temu i myślę, że byłaby to akceptowana odpowiedź, gdyby ktoś chciał opublikować go jako taki ...
Asu

1
@Asu, tak, pomyślałem o obejściu problemu ręcznie. Byłoby to denerwujące, ale muszę przyznać, że nie zdawałem sobie sprawy, że istnieją emulatory terminali obsługujące kopiowanie kart. Zmiana na taką, która jest, byłaby oczywiście znacznie lepszym rozwiązaniem!
ilkkachu

4

W printf '%s\t%s\n' foo bar, printfrobi wyjście foo<TAB>bar<LF>.

f, o, b, aI rsą to pojedyncze szerokości znaków graficznych.

Po otrzymaniu tych znaków terminal wyświetli odpowiedni glif i przesunie kursor o jedną kolumnę w prawo, chyba że osiągnął już prawą krawędź ekranu (papier w oryginalnych maszynach do pisania na maszynie)), w którym to przypadku może podać linię i wróć do lewej krawędzi ekranu (zawiń) lub po prostu odrzuć znak w zależności od terminala i jego konfiguracji.

<Tab>i <LF>są dwoma znakami kontrolnymi . <LF>(aka newline) to separator linii w tekście uniksowym, ale dla terminali po prostu podaje linię (przesuń kursor o jedną pozycję w dół). Tak więc sterownik terminala w jądrze faktycznie go przetłumaczy <CR>(powrót do lewej krawędzi ekranu), <LF>(kursor w dół) ( stty onlcrzazwyczaj domyślnie włączony).

<Tab> mówi terminalowi, aby przesunął kursor do następnego tabulatora (który w większości terminali jest domyślnie oddalony o 8 pozycji, ale można go również skonfigurować do ustawienia w dowolnym miejscu) bez wypełniania odstępu pustymi miejscami.

Jeśli więc te znaki są wysyłane do terminala z tabulatorami co 8 kolumn, gdy kursor znajduje się na początku pustej linii, spowoduje to:

foo     bar

wydrukowany na ekranie w tej linii. Jeśli zostaną wysłane, gdy kursor znajduje się na trzeciej pozycji w linii zawierającej xxxxyyyyzzzz, spowoduje to:

xxfooyyybarz

W terminalach, które nie obsługują tabulacji, sterownik terminala można skonfigurować tak, aby tłumaczył te tabulatory na sekwencje spacji. ( stty tab3).

Znak SPC w oryginalnych maszynach do pisania przesuwałby kursor w prawo, a backspace ( \b) - w lewo. Teraz w nowoczesnych terminalach SPC przesuwa się w prawo, a także usuwa (zapisuje spację, jak można się spodziewać). Dlatego wisiorek \bmusiał być czymś nowszym niż ASCII. W większości nowoczesnych terminali, to faktycznie ciągiem znaków: <Esc>, [, C.

Dostępnych jest więcej sekwencji ucieczki do przesuwania npostaci w lewo, w prawo, w górę, w dół lub w dowolnej pozycji na ekranie. Istnieją inne sekwencje specjalne do wymazywania (wypełniania pustych) części linii lub obszarów ekranu itp.

Sekwencje te są zazwyczaj używane przez aplikacje wizualnych, takich jak vi, lynx, mutt, dialoggdzie tekst jest napisany w dowolnych pozycjach na ekranie.

Teraz wszystkie emulatory terminali X11 i kilka innych niż X11, takie jak GNU, screenpozwalają wybrać obszary ekranu do wklejenia. Po wybraniu części tego, co widzisz w viedytorze, nie chcesz kopiować wszystkich sekwencji specjalnych, które zostały użyte do wytworzenia tego wyniku. Chcesz zaznaczyć tekst, który tam widzisz.

Na przykład, jeśli uruchomisz:

printf 'abC\rAC\bB\t\e[C\b\bD\n'

Który symuluje sesji edytora gdzie można wejść abC, wróć do początku, wymienić abz AC, Cz B, przejść do następnego tabulatora, a następnie jeszcze jedną kolumnę w prawo, a następnie dwie kolumny po lewej stronie, a następnie wprowadzić D.

Zobaczysz:

ABC    D

To znaczy, ABC4-kolumnowa przerwa i D.

Jeśli wybierzesz tę opcję za pomocą myszy w xtermlub putty, będą one przechowywać w zaznaczeniu ABC4 znaki spacji, a Dnie abC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D.

To, co kończy się w selekcji, to to, co zostało wysłane, printfale przetworzone przez sterownik terminala i emulator terminala.

W przypadku innych rodzajów transformacji zobacz <U+0065><U+0301>( enastępnie łączący ostry akcent) zmieniony na <U+00E9>( éforma wstępnie skomponowana) przez xterm.

Lub echo abcto ostatecznie zostanie przetłumaczone ABCprzez kierowcę terminala przed wysłaniem do terminala po stty olcuc.

Teraz, <Tab>podobnie jak <LF>jeden z niewielu znaków kontrolnych, które tak naprawdę czasami znajdują się w plikach tekstowych (także <CR>w plikach tekstowych MSDOS, a czasem <FF>do podziału strony).

Tak więc niektóre emulatory terminali decydują się na kopiowanie ich, gdy jest to możliwe, w buforach kopiuj-wklej, aby je zachować (generalnie tak nie jest <CR>ani tak <LF>nie jest).

Na przykład, w terminalach opartych na VTE, takich jak gnome-terminal, możesz zobaczyć, że kiedy wybierzesz wyjście printf 'a\tb\n'w pustym wierszu, gnome-terminalfaktycznie zapisujesz a\tbwybór X11 zamiast a7 spacji i b.

Ale na wyjściu printf 'a\t\bb\n', przechowuje a, 6 pomieszczeń i b, a dla printf 'a\r\tb\n', a7 miejsc i b.

Istnieją inne przypadki, w których terminale spróbują skopiować rzeczywiste dane wejściowe, na przykład po wybraniu dwóch linii po uruchomieniu, w printf 'a \nb\n'których zostanie zachowana niewidoczna końcowa przestrzeń. Lub przy wyborze dwóch linii nie zawiera znaku LF, gdy dwie linie wynikają z zawijania na prawym marginesie.

Teraz, jeśli chcesz zapisać dane wyjściowe printfw SCHOWKU X11wybierz, najlepiej zrobić to bezpośrednio, jak w przypadku:

printf 'foo\tbar\n' | xclip -sel c

Należy pamiętać, że po wklejeniu, że w xtermprzypadku większości innych terminali, xtermfaktycznie zastępuje \nsię \rbo to postać xtermwysyła po naciśnięciu Enter(i kierowca terminal może przełożyć go z powrotem \n).


To bardzo wnikliwe, dziękuję. Wypróbowałem rozwiązanie xclip i działa. Ale nie robi dokładnie tego, co miałem na myśli i wymaga X11. Być może przyda się to w pewnym momencie, dzięki!
Asu

@Asu, X11to, co obsługuje wybór kopiuj-wklej w emulatorach terminali, takich jak xtermlub puttyna Uniksie. Inne emulatory terminali mogą mieć własny mechanizm kopiuj-wklej i sposoby przechowywania dowolnych treści, takich jak polecenia readbuf i registerna ekranie GNU.
Stéphane Chazelas,
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.