Come stampare stringhe separate da TAB in bash?


9

Sto cercando di stampare due stringhe separate da una TAB. Ho provato:

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

Entrambi stampano:

foo     bar

Dove lo spazio bianco tra i due è in realtà 5 spazi (secondo la selezione dell'output con il mouse in Putty).

Ho anche provato a usare CTRL + V e premendo TAB durante la digitazione del comando, con lo stesso risultato.

Qual è il modo corretto di forzare la stampa della scheda come scheda, in modo da poter selezionare l'output e copiarlo da qualche altra parte, con le schede?

E la domanda secondaria: perché bash espande le schede negli spazi?

Aggiornamento : Apparentemente, questo è un problema di Putty: /superuser/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changing-them-to -spaces



Perché non sfuggire? printf '%s\\t%s\n' foo bar
Valentin Bajrami,

@steeldriver Grazie è molto simile a quello di cui ho bisogno, ma alla fine non esiste una soluzione ...
Asu,

1
@Valentin That output foo\tbar...
wjandrea il

1
Nonostante il fatto che sai già di avere un problema con il tuo terminale: Bash da solo interpreta $'\t'come tabulatore. Quindi puoi sempre concatenare stringhe come questa - ad esempio come compito: v='This is'$'\t''a test'e printf '%s' "$v"
stampalo

Risposte:


9

Come ha detto ilkkachu, questo non è un problema con bash, ma con l'emulatore di terminale che converte le schede in spazi sull'output.

Controllando diversi terminali, putty, xterm e konsole convertono le schede in spazi, mentre urxvt e gnome-terminal no. Quindi, un'altra soluzione è quella di cambiare terminale.


3
Può anche essere eseguito dal driver tty dopo l'esecuzione stty tab3.
Stéphane Chazelas,

14

lo spazio bianco tra i due è in realtà 5 spazi.

No non lo è. Non nell'output di echoo printf.

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

Qual è il modo corretto di forzare la stampa della scheda come scheda, in modo da poter selezionare l'output e copiarlo da qualche altra parte, con le schede?

Questo è un problema diverso. Non si tratta della shell ma dell'emulatore di terminale, che converte le schede in spazi sull'output. Molti, ma non tutti lo fanno.

Potrebbe essere più semplice reindirizzare l'output con le schede in un file e copiarlo da lì, oppure utilizzarlo unexpandsull'output per convertire gli spazi in schede. (Anche se non può nemmeno sapere con quale spazio bianco fossero le schede per cominciare e, se possibile, convertirà tutto in schede.) Questo ovviamente dipenderà da cosa, esattamente, devi fare con l'output.


Volevo dire che quando provo a selezionare l'output, viene trattato come 5 spazi. Grazie per "od -c" per verificare il contenuto dell'output del comando.
Asu,

1
@Asu Penso che lo capisca. La sua soluzione è ottenere l'output con altri mezzi poiché l'emulatore di terminale non garantisce che lasci le schede come schede quando le selezioni nella finestra. Tuttavia, ho appena controllato e mentre putty, xterm e konsole convertono le schede in spazi, urxvt e gnome-terminal no. Quindi, un'altra soluzione è quella di cambiare terminale.
JoL

@JoL Sì, questa è la conclusione che ho appena raggiunto un minuto fa, e penso che sarebbe la risposta accettata se qualcuno si preoccupasse di pubblicarla come tale ...
Asu

1
@Asu, sì, ho pensato di risolvere manualmente il problema. Sarebbe fastidioso doverlo fare, ma poi ammetto di non essermi reso conto che ci sono emulatori terminali che supportano le schede di copia. Passare a uno che lo fa, ovviamente sarebbe una soluzione molto migliore!
ilkkachu,

4

In printf '%s\t%s\n' foo bar, printfgenera output foo<TAB>bar<LF>.

f, o, b, aE rsono i caratteri grafici a singola larghezza.

Dopo aver ricevuto quei caratteri, il terminale visualizzerà un glifo corrispondente e sposta il cursore di una colonna a destra, a meno che non abbia già raggiunto il bordo destro dello schermo (carta nelle tele-macchine da scrivere originali)), nel qual caso può alimentare una linea e tornare al bordo sinistro dello schermo (a capo) o semplicemente scartare il personaggio a seconda del terminale e di come è stato configurato.

<Tab>e <LF>sono due personaggi di controllo . <LF>(aka newline) è il delimitatore di riga nel testo Unix, ma per i terminali alimenta solo una linea (sposta il cursore di una posizione verso il basso). Quindi il driver del terminale nel kernel lo tradurrà effettivamente in <CR>(torna al bordo sinistro dello schermo), <LF>(cursore in basso) ( stty onlcrgeneralmente acceso di default).

<Tab> indica al terminale di spostare il cursore sul tab stop successivo (che sulla maggior parte dei terminali sono 8 posizioni distinte per impostazione predefinita, ma può anche essere configurato per essere impostato ovunque) senza riempire il vuoto con spazi vuoti.

Pertanto, se quei caratteri vengono inviati a un terminale con tabulazioni ogni 8 colonne mentre il cursore si trova all'inizio di una riga vuota, ciò comporterà:

foo     bar

stampato sullo schermo su quella linea. Se vengono inviati mentre il cursore si trova in terza posizione in una riga che contiene xxxxyyyyzzzz, ciò comporterà:

xxfooyyybarz

Sui terminali che non supportano la tabulazione, il driver del terminale può essere configurato per tradurre quelle schede in sequenze di spazi. ( stty tab3).

Il carattere SPC, nelle macchine da scrivere originali, spostava il cursore a destra, mentre backspace ( \b) lo spostava a sinistra. Ora nei terminali moderni, SPC si sposta a destra e cancella anche (scrive un carattere spaziale come ci si aspetterebbe). Quindi il pendente di \bdoveva essere qualcosa di più nuovo di ASCII. Sulla maggior parte dei terminali moderni, in realtà è una sequenza di caratteri: <Esc>, [, C.

Esistono più sequenze di escape per spostare i npersonaggi a sinistra, a destra, in alto, in basso o in qualsiasi posizione sullo schermo. Esistono altre sequenze di escape per cancellare (riempire con spazi vuoti) parti di linee o aree dello schermo, ecc.

Tali sequenze sono tipicamente utilizzati per applicazioni visivi come vi, lynx, mutt, dialogin cui il testo è scritto in posizioni arbitrarie sullo schermo.

Ora, tutti gli emulatori di terminale X11 e alcuni altri non X11 come GNU screenti consentono di selezionare le aree dello schermo per il copia incolla. Quando selezioni una parte di ciò che vedi vinell'editor, non vuoi copiare tutte le sequenze di escape utilizzate per produrre quell'output. Vuoi selezionare il testo che vedi lì.

Ad esempio se esegui:

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

Il che simula una sessione dell'editor in cui si entra abC, si torna all'inizio, si sostituisce abcon AC, Ccon B, si passa alla successiva tabulazione, quindi un'altra colonna a destra, quindi due colonne a sinistra, quindi si entra D.

Vedi:

ABC    D

Cioè ABC, un gap di 4 colonne e D.

Se lo selezioni con il mouse in xtermo putty, memorizzeranno nella selezione ABC4 caratteri spaziali e Dnon abC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D.

Ciò che finisce nella selezione è ciò che è stato inviato printfma post-elaborato sia dal driver del terminale che dall'emulatore di terminale.

Per altri tipi di trasformazione, vedere <U+0065><U+0301>( eseguito da un accento acuto combinato) modificato in <U+00E9>( éla forma precomposta) da xterm.

O echo abcche finisce per essere tradotto ABCdal driver del terminale prima di inviarlo al terminale dopo un stty olcuc.

Ora, <Tab>come <LF>è uno di quei pochi caratteri di controllo che a volte si trovano effettivamente nei file di testo (anche <CR>nei file di testo MSDOS e talvolta <FF>per l'interruzione di pagina).

Quindi alcuni emulatori di terminali scelgono di copiarli quando possibile nei buffer di copia e incolla per preservarli (generalmente non è il caso <CR>né il caso <LF>).

Ad esempio, in terminali basati su VTE come gnome-terminal, potresti vedere che, quando selezioni l'output printf 'a\tb\n'su una riga vuota, in gnome-terminalrealtà memorizza a\tbnella selezione X11 anziché a7 spazi e b.

Ma per l'output di printf 'a\t\bb\n', memorizza a, 6 spazi e b, e printf 'a\r\tb\n', per a, 7 spazi e b.

Ci sono altri casi in cui i terminali proveranno a copiare l'input effettivo, come quando si selezionano due righe dopo l'esecuzione in printf 'a \nb\n'cui verrà preservato quello spazio finale invisibile. O quando si selezionano due righe non include un carattere LF quando le due righe risultano dall'avvolgimento sul margine destro.

Ora, se si desidera memorizzare l'output printfnella X11selezione CLIPBOARD , la cosa migliore è farlo direttamente come con:

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

Nota che quando lo incolli in xtermo nella maggior parte degli altri terminali, in xtermrealtà lo sostituisce \ncon \rperché questo è il carattere che xterminvia quando premi Enter(e il driver del terminale può riportarlo in \n).


Questo è molto penetrante, grazie. Ho provato la soluzione xclip e funziona. Ma non fa esattamente quello che avevo in mente e richiede X11. Potrebbe essere utile a un certo punto, grazie!
Asu,

@Asu, X11è ciò che gestisce la selezione copia-incolla in emulatori di terminale come xtermo puttysu Unix. Altri emulatori di terminali possono avere il proprio meccanismo di copia-incolla e modi per memorizzare contenuti arbitrari, come i comandi readbuf e registernella schermata GNU.
Stéphane Chazelas il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.