TAB
Символ являє собою керуючий символ , який при відправці на terminal¹ робить рух курсора терміналу до наступної закладки зупинки. За замовчуванням у більшості терміналів зупинки вкладок розташовані на 8 стовпців, але це налаштовується.
Ви також можете мати зупинки вкладок з нерегулярними інтервалами:
$ tabs 3 9 11; printf '\tx\ty\tz\n'
x y z
Тільки термінал знає, на скільки стовпців праворуч TAB перемістить курсор.
Ви можете отримати цю інформацію, запитуючи позицію курсору з терміналу до та після відправлення вкладки.
Якщо ви хочете зробити цей розрахунок вручну для даного рядка і припускаючи, що цей рядок друкується в першому стовпці екрана, вам потрібно буде:
- знати, де стоять вкладки²
- знати ширину відображення кожного символу
- знати ширину екрана
- вирішіть, чи хочете ви обробляти інші символи управління
\r
(наприклад, що переміщує курсор до першого стовпця) або \b
переміщувати курсор назад ...)
Це може бути спрощено, якщо ви припускаєте, що зупинки вкладки є кожні 8 стовпців, рядок вписується на екран і немає інших контрольних символів або символів (або не символів), які ваш термінал не може відображатись належним чином.
З GNU wc
, якщо рядок зберігається у $line
:
width=$(printf %s "$line" | wc -L)
width_without_tabs=$(printf %s "$line" | tr -d '\t' | wc -L)
width_of_tabs=$((width - width_without_tabs))
wc -L
дає ширину найширшої лінії у своєму введенні. Це робить, використовуючи wcwidth(3)
для визначення ширини символів і припускаючи, що зупинки вкладки є кожні 8 стовпців.
Щодо систем, що не належать до GNU, та з тими ж припущеннями, див. Підхід @ Кусалаланда . Це ще краще, оскільки дозволяє вказати зупинки вкладок, але, на жаль, наразі не працює з GNU expand
(принаймні), коли вхід містить багатобайтові символи або символи 0-ширини (як поєднання символів) або подвійну ширину символів.
Though зауважте, що якщо ви це зробите stty tab3
, дисципліна лінії tty пристрою візьме на себе обробку вкладок (перетворіть TAB в пробіли, виходячи з власного уявлення про те, де міг би знаходитися курсор перед відправленням в термінал), і впроваджувати вкладку зупинятиме кожні 8 стовпців. Тестуючи на Linux, схоже, що він обробляє належним чином символи CR, LF та BS, а також багатобайтові символи UTF-8 (надається iutf8
також увімкнено), але це стосується цього. Він передбачає, що всі інші символи без керування (включаючи нульову ширину, подвійну ширину символів) мають ширину 1, він (очевидно) не обробляє послідовності втечі, не обертається належним чином ... Це, мабуть, призначене для терміналів, які не вдається обробити вкладку.
У будь-якому випадку, дисципліна tty line повинна знати, де знаходиться курсор, і використовує ті евристики, наведені вище, тому що при використанні icanon
редактора рядків (наприклад, коли ви вводите текст для таких програм cat
, які не реалізують власний редактор рядків), коли ви натисніть TabBackspace, дисципліна рядка повинна знати, скільки символів BS надіслати, щоб видалити цей символ Tab для відображення. Якщо змінити місце зупинки вкладки (наприклад, з tabs 12
), ви помітите, що вкладки не стираються належним чином. Те саме, якщо ви вводите символи подвійної ширини перед натисканням TabBackspace.
² Для цього ви можете надсилати символи табуляції та запитувати положення курсору після кожного. Щось на зразок:
tabs=$(
saved_settings=$(stty -g)
stty -icanon min 1 time 0 -echo
gawk -vRS=R -F';' -vORS= < /dev/tty '
function out(s) {print s > "/dev/tty"; fflush("/dev/tty")}
BEGIN{out("\r\t\33[6n")}
$NF <= prev {out("\r"); exit}
{print sep ($NF - 1); sep=","; prev = $NF; out("\t\33[6n")}'
stty "$saved_settings"
)
Потім ви можете використовувати це як expand -t "$tabs"
рішення @ Kusalananda.
x
), перш ніж викликатиexpand
інше, ви також будете рахувати пробіли, які були спочатку на вході.