Як друкувати рядки, розділені TAB в bash?


9

Я намагаюся надрукувати два рядки, розділені TAB. Я намагався:

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

Вони друкують:

foo     bar

Де пробіл між двома насправді є 5 пробілами (відповідно до вибору виводу за допомогою миші в Putty).

Я також намагався використовувати CTRL + V і натискати TAB під час введення команди, з тим же результатом.

Який правильний спосіб змусити друкувати вкладку як табуляцію, щоб я міг вибрати вихід і скопіювати його кудись ще, за допомогою вкладок?

І другорядне питання: чому bash розширює вкладки на пробіли?

Оновлення : Мабуть, це проблема Putty: /superuser/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changing-them-to -простори



Чому просто не уникнути цього? printf '%s\\t%s\n' foo bar
Валентин Байрамі

@steeldriver Дякую, це дуже схоже на те, що мені потрібно, але в кінцевому підсумку рішення не знайдеться ...
Asu

1
@Valentin Що виводить foo\tbar...
wjandrea

1
Незважаючи на той факт, що ви вже знаєте, що у вас є проблема зі своїм терміналом: Bash сам по собі інтерпретує $'\t'як табулятор. Таким чином, ви завжди можете об'єднати такі рядки - наприклад, як призначення: v='This is'$'\t''a test'І роздрукувати це буквально, наприкладprintf '%s' "$v"
rexkogitans

Відповіді:


9

Як сказав ilkkachu, це не проблема з bash, а з термінальним емулятором, який перетворює вкладки в пробіли на виході.

Перевірка різних терміналів, putty, xterm та konsole перетворює вкладки в пробіли, тоді як urxvt та gnome-terminal не роблять. Отже, ще одне рішення - переключити клеми.


3
Це також може зробити драйвер tty після запуску stty tab3.
Стефан Шазелас

14

пробіл між ними - це фактично 5 пробілів.

Ні це не так. Не у виході echoабо printf.

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

Який правильний спосіб змусити друкувати вкладку як табуляцію, щоб я міг вибрати вихід і скопіювати його кудись ще, за допомогою вкладок?

Це вже інше питання. Йдеться не про оболонку, а про термінальний емулятор, який перетворює вкладки у пробіли на виході. Багато хто, але не всі вони так роблять.

Можливо, буде простіше перенаправити вихід з вкладками на файл і скопіювати його звідти або використовувати unexpandна виході для перетворення пробілів у вкладки. (Хоча він також не може знати, з якого пробілу були вкладки для початку, і перетворить усе це на вкладки, якщо це можливо.) Це, звичайно, залежатиме від того, що саме потрібно робити з результатом.


Я мав на увазі, що коли я намагаюся вибрати вихід, це трактується як 5 пробілів. Дякую за команду 'od -c' для перевірки вмісту команди.
Асу

1
@Asu я думаю, що він це розуміє. Його рішення полягає в отриманні виводу за допомогою інших засобів, оскільки емулятор терміналу не гарантовано залишає вкладки як вкладки, коли ви вибираєте їх у вікні. Однак я просто перевірив, і в той час як putty, xterm і konsole перетворюють вкладки в пробіли, urxvt та gnome-terminal не роблять. Отже, ще одне рішення - переключити клеми.
JoL

@JoL Так, до цього висновку я прийшов лише хвилину тому, і я думаю, що це було б прийнятою відповіддю, якщо хтось захоче опублікувати його як таке ...
Asu

1
@Ага, так, я думав про те, щоб просто вирішити проблему вручну. Було б прикро це робити, але тоді я визнаю, що не розумів, що є емулятори терміналів, які підтримують копіювання вкладок. Зміна на іншу, яка, звичайно, була б набагато кращим рішенням!
ilkkachu

4

В printf '%s\t%s\n' foo bar, printfробить вихід foo<TAB>bar<LF>.

f, o, b, aІ rє однією шириною графічних символів.

Після отримання цих символів термінал відобразить відповідний гліф і перемістить курсор на один стовпець праворуч, якщо тільки він вже не досяг правого краю екрана (папір на оригінальних машинописних машинках)), і в цьому випадку він може подати рядок і поверніться до лівого краю екрана (обгортання) або просто відкиньте символ залежно від терміналу та способу його налаштування.

<Tab>і <LF>є двома контрольними символами. <LF>(також новий рядок) - це роздільник рядків у тексті Unix, але для терміналів він просто подає рядок (перемістіть курсор на одну позицію вниз). Таким чином драйвер терміналу в ядрі фактично переведе його на <CR>(повернення в лівий край екрану), <LF>(курсор вниз) ( stty onlcrяк правило, за замовчуванням).

<Tab> повідомляє терміналу перемістити курсор до наступної зупинки вкладки (яка на більшості терміналів за замовчуванням розташована на 8 позицій, але їх можна також налаштувати для встановлення в будь-якому місці), не заповнюючи пробіл пробілами.

Тож якщо ці символи надсилаються до терміналу з зупинками на вкладці кожні 8 стовпців, поки курсор знаходиться на початку порожнього рядка, це призведе до:

foo     bar

надруковано на екрані в цьому рядку. Якщо вони будуть надіслані, поки курсор знаходиться на третьому положенні у рядку, який містить xxxxyyyyzzzz, це призведе до:

xxfooyyybarz

На терміналах, які не підтримують табуляцію, драйвер терміналу можна налаштувати для перекладу цих вкладок у послідовності пробілів. ( stty tab3).

Символ SPC в оригінальних машинописних машинках переміщуватиме курсор праворуч, тоді як backspace ( \b) переміщує його вліво. Тепер у сучасних терміналах SPC переміщується вправо і також стирається (пише пробільний символ, як ви очікували). Тож кулон \bповинен був бути чимось новішим, ніж ASCII. На більшості сучасних терміналів, насправді це послідовність символів: <Esc>, [, C.

Існує більше послідовностей евакуації для переміщення nсимволів вліво, вправо, вгору, вниз або в будь-яку позицію на екрані. Існують і інші послідовності евакуації для видалення (заповнення порожнім) частин рядків або областей екрана тощо.

Ці послідовності , як правило , використовується візуальними додатками , таких як vi, lynx, mutt, dialogде текст написаний в довільних позиціях на екрані.

Тепер усі емулятори терміналів X11 та деякі інші не-X11 такі, як GNU, screenдозволяють вам вибирати області екрану для копіювання. Коли ви вибираєте частину побаченого в viредакторі, ви не хочете копіювати всі послідовності евакуації, які використовувались для отримання цього виводу. Ви хочете вибрати текст, який ви бачите там.

Наприклад, якщо ви працюєте:

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

Що імітує редактор сеансу , коли ви входите abC, повернутися до початку, замініть abз AC, Cз B, перейти на наступну позицію табуляції, а потім ще один стовпець вправо, потім два стовпці зліва, а потім ввести D.

Розумієш:

ABC    D

Тобто, ABCпроміжок у 4 стовпчиках і D.

Якщо ви виберете, що за допомогою миші вказується xtermабо putty, вони зберігатимуть у ABCвиділеному знаку 4 пробіли та D, ні abC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D.

У виборі закінчується те, що було надіслано, printfале після обробки як драйвером терміналу, так і емулятором терміналу.

Для інших видів трансформації див. <U+0065><U+0301>eподальшим поєднанням гострого акценту), змінений на <U+00E9>( éзаздалегідь складена форма) на xterm.

Або echo abcце в кінцевому підсумку переводиться ABCдрайвером терміналу перед відправкою в термінал після stty olcuc.

Зараз, <Tab>начебто, <LF>це один з тих небагатьох керуючих символів, які насправді іноді зустрічаються у текстових файлах (також <CR>у текстових файлах MSDOS, а іноді і <FF>при розриві сторінки).

Тому деякі емулятори терміналів вирішують скопіювати їх, коли це можливо, в буфери копіювання-вставки, щоб зберегти їх (це, як правило, не має значення <CR>ні <LF>хоч).

Наприклад, у терміналах на базі VTE gnome-terminal, можливо, ви побачите, що, коли ви вибираєте вихід printf 'a\tb\n'на порожній рядку, gnome-terminalнасправді зберігається a\tbу виді X11 замість a7 пробілів і b.

Але для виведення printf 'a\t\bb\n', він зберігає a, 6 місць і b, і для printf 'a\r\tb\n', a, 7 просторів і b.

Є й інші випадки, коли термінали намагаються скопіювати фактичний вхід, як, наприклад, після вибору двох рядків після запуску, printf 'a \nb\n'де буде збережено цей невидимий простір. Або при виборі двох рядків не міститься символ LF, коли два рядки є результатом обгортання з правого поля.

Тепер, якщо ви хочете зберегти вихід printfу CLIPBOARD X11select, найкраще це зробити безпосередньо так:

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

Зверніть увагу , що при вставці , що xtermі більшість інших терміналів, xtermфактично замінює , що \nз , \rтому що це символ xtermпосилає при натисканні Enter(і драйвер терміналу може перевести його назад \n).


Це дуже проникливо, дякую. Я спробував рішення xclip і воно працює. Але це не робить саме те, що я мав на увазі, і вимагає X11. Можливо, це стане в нагоді в якийсь момент, дякую!
Асу

@Asu - X11це те, що обробляє вибір копіювання-вставки в емуляторах терміналів, таких як xtermабо puttyна Unix. Інші емулятори терміналів можуть мати власний механізм копіювання-вставки та способи зберігання довільного вмісту, наприклад, readbuf та registerкоманд на екрані GNU.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.