Si noti che dalla versione 292 , xterm rimuove i caratteri di controllo ASCII ad eccezione di \b
, \r
, \t
, DEL
(0x7f) e \n
(converte \n
in \r
s come altri terminali) e puoi riportarli con la risorsa allowPasteControls
. VTE (la libreria dell'emulatore di terminale utilizzata da gnome-terminal
, terminator
, xfce-terminal
...) anche lo fa da ottobre 2015
Quindi in quei terminali, ^C
, ^[
, ^D
, ^Z
, ^\
, ^U
, ^W
non sono più un problema ma DEL, \b
, \t
(molto pericoloso con alcune configurazioni (inclusa quella di default) di zsh
dove il completamento può espandere le sostituzioni di comando), \r
e \n
lo sono ancora.
xterm
ha anche un paio di modalità di incollamento che possono aiutarti qui.
-
la modalità di scrittura tra parentesi attivata con la sequenza \e[?2004h
utilizzata in alcuni zsh o vim sicuri - incolla plug-in .
zsh
( zle
) dal 5.1 e bash
( readline
) da 4.4 ora hanno il supporto per quello integrato. Mentre è abilitato per impostazione predefinita in zsh
, devi abilitarlo manualmente con bind 'set enable-bracketed-paste on'
in bash
(o nella configurazione readline
in ~/.inputrc
o /etc/inputrc
).
Questo avvolge la selezione tra \e[200~
e \e[201~
.
La maggior parte degli altri terminali moderni come quelli basati su VTE ( gnome-terminal
, xfce-terminal
, terminator
...), rxvt
, konsole
, OS / X Terminal
ora supportano anche quello.
In alcuni di quegli altri terminali (o versioni di questi) però (o con allowPasteControls
in xterm
), ciò è difettoso in quanto \e[201~
potrebbe apparire nella selezione, e sarebbe preso come parentesi di chiusura.
Potrebbe essere risolto da bracketing come \e\e[201~\e[200~201~
, ma non è ancora stato eseguito da alcun emulatore di terminale AFAIK (e significherebbe che l'applicazione vedrebbe più paste).
Anche ^C
/ ^Z
/ ^\
causerebbe ancora l'invio di segnali al gruppo di processi in foreground del terminale se ISIG
non è stato disabilitato nella disciplina della linea tty.
-
La modalità Incolla quotata abilitata con la sequenza \e[?2005h
(disabilitata con \e[?2005l
).
Questo antepone ogni carattere (in realtà un byte) con un carattere ^V
.
^V
è il carattere predefinito lnext
( letterale successivo ) della disciplina della linea tty in modalità canonica ed è anche riconosciuto come tale da vi
e altri editor e alcuni editor di righe come readline o zsh
s zle.
Questo non ha lo stesso problema della modalità con parentesi sopra, e ha il vantaggio di funzionare per la modalità canonica del terminale (come quando fai cat > file
) e alcune altre applicazioni ma ha alcuni inconvenienti:
- newline e CR finiscono per essere resi come
^M
. Ciò può essere evitato con un'altra sequenza di escape: \e[?2006h
, ma ciò fa sì che le newline vengano inserite come caratteri NUL in vim
e mostrino come ^J
(a meno che non si faccia stty -echoctl
) nella modalità canonica terminale (sebbene è solo un problema estetico).
- Non funziona molto bene per i caratteri multi-byte che non sono inseriti correttamente in
zle
o vim
per esempio.
- alcune applicazioni visive non gestiscono
^V
come literal next , quindi potresti dover ancora disattivarlo in modo selettivo.
- non puoi usarlo in
vim
come ^V 1
per esempio non inserisce 1
ma ^A
lì.
- Non sono a conoscenza di nessun altro terminale accanto a
xterm
che lo supporta, ma poi non ho fatto un sondaggio completo.
-
ti consente anche di definire la tua modalità di incollaggio tra parentesi tramite la configurazione. Ad esempio, con:
XTerm*allowPasteControls: true
XTerm.VT100.translations: #override \
Ctrl Shift<KeyPress> Insert: \
insert-formatted("3[202~%S~%s", CLIPBOARD,PRIMARY,CUT_BUFFER0)'
inserirà CLIPBOARD
/ PRIMARY
/ CUT_BUFFER0
come ^[[202~<size-in-bytes>~<content>
su Maiusc + Ctrl + Inserisci . L'applicazione potrebbe quindi interpretarla in modo affidabile (sarebbe comunque necessario disabilitare ISIG
nella disciplina della linea tty).
Un altro approccio sarebbe utilizzare un wrapper pseudo-tty che inserisca quei ^V
solo davanti ai caratteri di controllo. Tale wrapper dovrebbe essere in grado di rilevare i caratteri di controllo in paste con un po 'di affidabilità perché i tasti di tastiera reali manderebbero solo un carattere alla volta o una sequenza di caratteri che iniziano con ESC, mentre le paste invierebbero diverse alla volta .
Avresti ancora il problema delle newline mostrate come ^J
nella modalità canonica terminale o ^@
in vim
, ma con la cooperazione potrebbe essere aggirato con la shell
Una dimostrazione del concetto:
Da utilizzare ad esempio come:
./safe-paste bash
Per avviare una shell bash
sotto quel wrapper.
#!/usr/bin/perl
use IO::Pty;
use IO::Stty;
my $pty = new IO::Pty;
my $pid = fork();
die "Cannot fork" if not defined $pid;
unless ($pid) {
$pty->make_slave_controlling_terminal();
my $slave = $pty->slave();
close $pty;
$slave->clone_winsize_from(\*STDIN);
open(STDIN,"<&". $slave->fileno())
or die "Couldn't reopen STDIN for reading, $!\n";
open(STDOUT,">&". $slave->fileno())
or die "Couldn't reopen STDOUT for writing, $!\n";
open(STDERR,">&". $slave->fileno())
or die "Couldn't reopen STDERR for writing, $!\n";
close $slave;
exec(@ARGV);
die "Cannot exec(@ARGV): $!";
}
$pty->close_slave();
$SIG{WINCH} = sub {
$pty->slave->clone_winsize_from(\*STDIN);
};
my $old = IO::Stty::stty(\*STDIN, '-g');
IO::Stty::stty(\*STDIN, 'raw', '-echo');
$tty = fileno($pty);
my ($rin,$ein) = ('','','');
vec($rin, 0, 1) = 1;
vec($rin, $tty, 1) = 1;
vec($ein, $tty, 1) = 1;
my ($to_stdout, $to_tty) = ('', '');
my $eof;
$SIG{CHLD} = sub {$eof = 1};
until ($eof && $to_stdout eq '' && $to_tty eq '') {
my ($rout,$wout,$eout,$timeleft);
my $win = '';
vec($win, 0, 1) = 1 if ($to_stdout ne "");
vec($win, $tty, 1) = 1 if ($to_tty ne "");
($nfound,$timeleft) = select($rout=$rin,$wout=$win,$eout=$ein,undef);
if ($nfound > 0) {
if (vec($eout, $tty, 1)) {
print STDERR "Exception on $tty\n";
}
if (vec($rout, 0, 1)) {
my $buf;
if (sysread(STDIN, $buf, 4096)) {
if ($buf =~ /.[ XTerm*allowPasteControls: true
XTerm.VT100.translations: #override \
Ctrl Shift<KeyPress> Insert: \
insert-formatted("3[202~%S~%s", CLIPBOARD,PRIMARY,CUT_BUFFER0)'
-77]/ || $buf =~ /^(?:[./safe-paste bash
-24-7]|3.*?[~a-zA-NP-Z])./) {
$buf =~ s/[#!/usr/bin/perl
use IO::Pty;
use IO::Stty;
my $pty = new IO::Pty;
my $pid = fork();
die "Cannot fork" if not defined $pid;
unless ($pid) {
$pty->make_slave_controlling_terminal();
my $slave = $pty->slave();
close $pty;
$slave->clone_winsize_from(\*STDIN);
open(STDIN,"<&". $slave->fileno())
or die "Couldn't reopen STDIN for reading, $!\n";
open(STDOUT,">&". $slave->fileno())
or die "Couldn't reopen STDOUT for writing, $!\n";
open(STDERR,">&". $slave->fileno())
or die "Couldn't reopen STDERR for writing, $!\n";
close $slave;
exec(@ARGV);
die "Cannot exec(@ARGV): $!";
}
$pty->close_slave();
$SIG{WINCH} = sub {
$pty->slave->clone_winsize_from(\*STDIN);
};
my $old = IO::Stty::stty(\*STDIN, '-g');
IO::Stty::stty(\*STDIN, 'raw', '-echo');
$tty = fileno($pty);
my ($rin,$ein) = ('','','');
vec($rin, 0, 1) = 1;
vec($rin, $tty, 1) = 1;
vec($ein, $tty, 1) = 1;
my ($to_stdout, $to_tty) = ('', '');
my $eof;
$SIG{CHLD} = sub {$eof = 1};
until ($eof && $to_stdout eq '' && $to_tty eq '') {
my ($rout,$wout,$eout,$timeleft);
my $win = '';
vec($win, 0, 1) = 1 if ($to_stdout ne "");
vec($win, $tty, 1) = 1 if ($to_tty ne "");
($nfound,$timeleft) = select($rout=$rin,$wout=$win,$eout=$ein,undef);
if ($nfound > 0) {
if (vec($eout, $tty, 1)) {
print STDERR "Exception on $tty\n";
}
if (vec($rout, 0, 1)) {
my $buf;
if (sysread(STDIN, $buf, 4096)) {
if ($buf =~ /.[%pre%-77]/ || $buf =~ /^(?:[%pre%-24-7]|3.*?[~a-zA-NP-Z])./) {
$buf =~ s/[%pre%-77]/6$&/g;
# TODO: add UTF-8 sanitizing
$buf =~ y/\r/\n/;
}
$to_tty .= $buf;
} else {
$eof = 1;
vec($rin, 0, 1) = 0;
}
}
if (vec($rout, $tty, 1)) {
my $buf;
if (sysread($pty, $buf, 4096)) {
$to_stdout .= $buf;
} else {
$eof = 1;
vec($rin, $tty, 1) = 0;
$to_tty = '';
}
}
if ($to_tty ne '' && vec($wout, $tty, 1)) {
my $written = syswrite($pty, $to_tty);
$to_tty = substr($to_tty, $written) if $written;
}
if ($to_stdout ne '' && vec(wout, 1, 1)) {
my $written = syswrite(STDOUT, $to_stdout);
$to_stdout = substr($to_stdout, $written) if $written;
}
}
}
END{IO::Stty::stty(\*STDIN, $old)}
-77]/6$&/g;
# TODO: add UTF-8 sanitizing
$buf =~ y/\r/\n/;
}
$to_tty .= $buf;
} else {
$eof = 1;
vec($rin, 0, 1) = 0;
}
}
if (vec($rout, $tty, 1)) {
my $buf;
if (sysread($pty, $buf, 4096)) {
$to_stdout .= $buf;
} else {
$eof = 1;
vec($rin, $tty, 1) = 0;
$to_tty = '';
}
}
if ($to_tty ne '' && vec($wout, $tty, 1)) {
my $written = syswrite($pty, $to_tty);
$to_tty = substr($to_tty, $written) if $written;
}
if ($to_stdout ne '' && vec(wout, 1, 1)) {
my $written = syswrite(STDOUT, $to_stdout);
$to_stdout = substr($to_stdout, $written) if $written;
}
}
}
END{IO::Stty::stty(\*STDIN, $old)}
Un approccio migliore sarebbe probabilmente quello di utilizzare un gestore di appunti in cui è possibile specificare la modalità di incollamento e che contrassegnerebbe le selezioni potenzialmente pericolose.