Estou tentando imprimir duas strings separadas por um TAB. Eu tentei:
echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar
Ambos imprimem:
foo bar
Onde o espaço em branco entre os dois é na verdade 5 espaços (conforme selecionando a saída com o mouse no Putty).
Também tentei usar CTRL+V e pressionar TAB ao digitar o comando, com o mesmo resultado.
Qual é a maneira correta de forçar a impressão da guia como guia, para que eu possa selecionar a saída e copiá-la para outro lugar, com guias?
E a pergunta secundária: por que o bash está expandindo guias em espaços?
Atualização : Aparentemente, este é um problema do Putty: https://superuser.com/questions/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-change-them-to -espaços
Não, não é. Não na saída de
echo
ouprintf
.Esta é uma questão diferente. Não se trata do shell, mas do emulador de terminal, que converte as guias em espaços na saída. Muitos, mas nem todos fazem isso.
Pode ser mais fácil redirecionar a saída com tabulações para um arquivo e copiá-la de lá ou usar
unexpand
na saída para converter espaços em tabulações. (Embora ele também não possa saber quais espaços em branco eram guias para começar, e converterá tudo em guias, se possível.) Isso obviamente dependeria do que, exatamente, você precisa fazer com a saída.Como ilkkachu disse, isso não é um problema com o bash, mas com o emulador de terminal que converte guias em espaços na saída.
Verificando diferentes terminais, putty, xterm e konsole convertem guias em espaços, enquanto urxvt e gnome-terminal não. Então, outra solução é trocar os terminais.
Em
printf '%s\t%s\n' foo bar
,printf
faz a saídafoo<TAB>bar<LF>
.f
,o
,b
e são caracteres gráficos de largura únicaa
.r
Ao receber esses caracteres, o terminal exibirá um glifo correspondente e moverá o cursor uma coluna para a direita, a menos que já tenha atingido a borda direita da tela (papel nas tele-máquinas de escrever originais)), caso em que poderá alimentar uma linha e volte para a borda esquerda da tela (wrap) ou apenas descarte o caractere dependendo do terminal e de como ele foi configurado.
<Tab>
e<LF>
são dois caracteres de controle .<LF>
(aka newline) é o delimitador de linha no texto Unix, mas para terminais, ele apenas alimenta uma linha (mova o cursor uma posição para baixo). Portanto, o driver do terminal no kernel o traduzirá para<CR>
(retornar à borda esquerda da tela),<LF>
(cursor para baixo) (stty onlcr
geralmente ativado por padrão).<Tab>
diz ao terminal para mover o cursor para a próxima parada de tabulação (que na maioria dos terminais estão separados por 8 posições por padrão, mas também pode ser configurado para ser definido em qualquer lugar) sem preencher a lacuna com espaços em branco.Portanto, se esses caracteres forem enviados para um terminal com paradas de tabulação a cada 8 colunas enquanto o cursor estiver no início de uma linha vazia, isso resultará em:
impresso na tela nessa linha. Se eles forem enviados enquanto o cursor estiver na terceira posição em uma linha que contém
xxxxyyyyzzzz
, isso resultará em:Em terminais que não suportam tabulação, o driver de terminal pode ser configurado para traduzir essas guias em sequências de espaços. (
stty tab3
).O caractere SPC, nas tele-máquinas de escrever originais, moveria o cursor para a direita, enquanto o backspace (
\b
) o moveria para a esquerda. Agora em terminais modernos, o SPC se move para a direita e também apaga (escreve um caractere de espaço como seria de esperar). Então o pingente de\b
tinha que ser algo mais novo que ASCII. Na maioria dos terminais modernos, é na verdade uma sequência de caracteres:<Esc>
,[
,C
.Existem mais sequências de escape para mover
n
os caracteres para a esquerda, direita, para cima, para baixo ou em qualquer posição na tela. Existem outras sequências de escape para apagar (preencher com branco) partes de linhas ou regiões da tela, etc.Essas sequências são normalmente usadas por aplicativos visuais como
vi
,lynx
,mutt
,dialog
onde o texto é escrito em posições arbitrárias na tela.Agora, todos os emuladores de terminal X11 e alguns outros não-X11, como
screen
o GNU, permitem selecionar áreas da tela para copiar e colar. Quando você seleciona uma parte do que vê novi
editor, não deseja copiar todas as sequências de escape que foram usadas para produzir essa saída. Você deseja selecionar o texto que você vê lá.Por exemplo, se você executar:
Que simula uma sessão do editor onde você entra
abC
, volta ao início, substituiab
porAC
,C
porB
, move para a próxima tabulação, depois mais uma coluna à direita, depois duas colunas à esquerda e depois entraD
.Você vê:
Ou seja,
ABC
, uma lacuna de 4 colunas eD
.Se você selecionar isso com o mouse em
xterm
ouputty
, eles armazenarão na seleçãoABC
4 caracteres de espaço eD
, nãoabC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D
.O que acaba na seleção é o que foi enviado,
printf
mas pós-processado, tanto pelo driver de terminal quanto pelo emulador de terminal.Para outros tipos de transformação, veja o
<U+0065><U+0301>
(e
seguido por um acento agudo combinado) alterado para<U+00E9>
(é
a forma pré-composta) porxterm
.Ou
echo abc
isso acaba sendo traduzidoABC
pelo driver do terminal antes de enviar para o terminal após um arquivostty olcuc
.Agora
<Tab>
, como<LF>
é um daqueles poucos caracteres de controle que às vezes são encontrados em arquivos de texto (também<CR>
em arquivos de texto MSDOS e às vezes<FF>
para quebra de página).Portanto, alguns emuladores de terminal optam por copiá-los quando possível nos buffers de copiar e colar para preservá-los (geralmente não é o caso de
<CR>
nem<LF>
embora).Por exemplo, em terminais baseados em VTE como
gnome-terminal
, você pode ver que, quando você seleciona a saída deprintf 'a\tb\n'
em uma linha vazia,gnome-terminal
na verdade armazenaa\tb
na seleção X11 em vez dea
, 7 espaços eb
.Mas para a saída de
printf 'a\t\bb\n'
, ele armazenaa
6 espaços eb
, e paraprintf 'a\r\tb\n'
,a
, 7 espaços eb
.Existem outros casos em que os terminais tentarão copiar a entrada real, como quando você seleciona duas linhas após executar
printf 'a \nb\n'
onde esse espaço invisível à direita será preservado. Ou ao selecionar duas linhas não inclui um caractere LF quando as duas linhas resultam de quebra na margem direita.Agora, se você deseja armazenar a saída
printf
no CLIPBOARDX11
select, o melhor é fazê-lo diretamente como com:Observe que quando você cola isso
xterm
ou na maioria dos outros terminais, naxterm
verdade substitui isso porque esse é o caractere enviado quando você pressiona (e o driver do terminal pode traduzi-lo de volta para ).\n
\r
xterm
Enter\n