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 이외의 시스템 및 동일한 가정에 대해서는 @Kusalananda의 접근법을 참조하십시오 . 탭 정지를 지정할 수 있기 때문에 더 낫지 만 불행히도 현재 expand
입력에 멀티 바이트 문자 또는 0 너비 (문자 결합과 같은) 또는 이중 너비 문자가 포함되어 있으면 GNU 에서 작동하지 않습니다 (적어도).
¹ 그러나 stty tab3
tty 디바이스 라인 규칙은 탭 처리를 인수하고 (터미널로 보내기 전에 커서가있을 수있는 위치에 대한 자체 아이디어에 따라 TAB을 공백으로 변환 함) 8 열마다 탭 중지를 구현합니다. Linux에서 테스트하면 CR, LF 및 BS 문자뿐만 아니라 멀티 바이트 UTF-8 문자 (제공된 iutf8
경우도 있음)를 올바르게 처리하는 것 같습니다 . 제어되지 않는 다른 모든 문자 (제로 너비, 두 배 너비 문자 포함)는 너비가 1이라고 가정하고 (분명히) 이스케이프 시퀀스를 처리하지 않으며 올바르게 줄 바꿈하지 않습니다 ... 아마도 터미널을위한 것입니다. 탭 처리를 수행 할 수 없습니다.
어떤 경우에는, 청각 장애 제어 규칙은 커서가하고 사용하는 경우 때문에, 위의 그 추론을 사용하여 위치를 알 필요하지 icanon
라인 에디터 (당신이 응용 프로그램에 텍스트를 입력 할 때 등이 같이 cat
그 자신의 라인 에디터를 구현하지 않습니다)를, 때를 을 누르면 TabBackspace라인 규칙 에 표시 할 탭 문자 를 지우기 위해 보낼 BS 문자 수를 알아야합니다 . 탭 정지 위치를 변경하면 (와 같이 tabs 12
) 탭이 제대로 지워지지 않습니다. 을 누르기 전에 2 바이트 문자를 입력하면 동일합니다 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
호출하기 전에 공백을 다른 1 바이트 문자 (예 :)로 바꾸고 싶을expand
때 입력에 있던 공백도 계산합니다.