Pipe to/from the clipboard in a Bash script - linux

Is it possible to pipe to/from the clipboard in Bash?
Whether it is piping to/from a device handle or using an auxiliary application, I can't find anything.
For example, if /dev/clip was a device linking to the clipboard we could do:
cat /dev/clip # Dump the contents of the clipboard
cat foo > /dev/clip # Dump the contents of "foo" into the clipboard

There are a wealth of clipboards you could be dealing with. I expect you're probably a Linux user who wants to put stuff in the X Windows primary clipboard. Usually, the clipboard you want to talk to has a utility that lets you talk to it.
In the case of X, there's xclip (and others). xclip -selection c will send data to the clipboard that works with Ctrl + C, Ctrl + V in most applications.
If you're on Mac OS X, there's pbcopy. E.g., cat example.txt | pbcopy
If you're in Linux terminal mode (no X) then look into gpm or Screen which has a clipboard. Try the Screen command readreg.
Under Windows 10+ or Cygwin, use /dev/clipboard or clip.

Make sure you are using alias xclip="xclip -selection c"
or else you won't be able to paste using Ctrl+v.
Example:
After running echo -n test | xclip, Ctrl+v will paste test

Install
# You can install xclip using `apt-get`
apt-get install xclip
# or `pacman`
pacman -S xclip
# or `dnf`
dnf install xclip
If you do not have access to apt-get nor pacman, nor dnf, the sources are available on sourceforge.
Set-up
Bash
In ~/.bash_aliases, add:
alias setclip="xclip -selection c"
alias getclip="xclip -selection c -o"
Do not forget to load your new configuration using . ~/.bash_aliases or by restarting your profile.
Fish
In ~/.config/fish/config.fish, add:
abbr setclip "xclip -selection c"
abbr getclip "xclip -selection c -o"
Do not forget to restart your fish instance by restarting your terminal for changes to apply.
Usage
You can now use setclip and getclip, e.g:
$ echo foo | setclip
$ getclip
foo

On macOS, use the built-in pbcopy and pbpaste commands.
For example, if you run
cat ~/.bashrc | pbcopy
the contents of the ~/.bashrc file will be available for pasting with the Cmd + V shortcut.
To save the current clipboard to a file, redirect the output pbpaste to a file:
pbpaste > my_clipboard.txt

2018 answer
Use clipboard-cli. It works with macOS, Windows, Linux, OpenBSD, FreeBSD, and Android without any real issues.
Install it with:
npm install -g clipboard-cli
Then you can do:
echo foo | clipboard
If you want, you can alias to cb by putting the following in your .bashrc, .bash_profile, or .zshrc:
alias cb=clipboard

xsel on Debian/Ubuntu/Mint
# append to clipboard:
cat 'the file with content' | xsel -ab
# or type in the happy face :) and ...
echo 'the happy face :) and content' | xsel -ib
# show clipboard
xsel -ob
# Get more info:
man xsel
Install
sudo apt-get install xsel

Try
xclip
xclip - command line interface to X selections (clipboard)
man

On the Windows Subsystem for Linux (WSL) you can copy to the clipboard with clip.exe:
cat file | clip.exe
Keep in mind to use the | pipe command. And not a > command, since that will not work.

Install the xcopy utility and when you're in the Terminal, input:
Copy
Thing_you_want_to_copy | xclip -selection c
Paste
myvariable=$(xclip -selection clipboard -o)
I noticed a lot of answers recommended pbpaste and pbcopy. If you're into those utilities, but for some reason they are not available in your repository, you can always make an alias for the xcopy commands and call them pbpaste and pbcopy.
alias pbcopy="xclip -selection c"
alias pbpaste="xclip -selection clipboard -o"
So then it would look like this:
Thing_you_want_to_copy | pbcopy
myvariable=$(pbpaste)
An answer located in one of the comments written by a user called doug work for me. Since I found it so helpful, I decided to restate in an answer.

Here is a ready-to-use Bash script for reading the clipboard which works on multiple platforms.
Please edit the script here if you add functionality (e.g., more platforms).
#!/bin/bash
# WF 2013-10-04
#
# Multi-platform clipboard read access
#
# Supports
# Mac OS X
# Git shell / Cygwin (Windows)
# Linux (e.g., Ubuntu)
#
# Display an error
#
error() {
echo "error: $1" 1>&2
exit 1
}
#
# getClipboard
#
function getClipboard() {
os=`uname`
case $os in
# Git Bash (Windows)
MINGW32_NT-6.1)
cat /dev/clipboard;;
# Mac OS X
Darwin*)
pbpaste;;
# Linux
Linux*)
# Works only for the X clipboard - a check that X is running might be due
xclip -o;;
*)
error "unsupported os $os";;
esac
}
tmp=/tmp/clipboard$$
getClipboard >$tmp
cat $tmp
# Comment out for debugging
rm $tmp

For Mac only:
echo "Hello World" | pbcopy
pbpaste
These are located /usr/bin/pbcopy and /usr/bin/pbpaste.

On Windows (with Cygwin) try
cat /dev/clipboard or echo "foo" > /dev/clipboard as mentioned in this article.

There are different clipboards in Linux; the X server has one, the window manager might have another one, etc. There is no standard device.
Oh, yes, on CLI, the screen program has its own clipboard as well, as do some other applications like Emacs and vi.
In X, you can use xclip.
You can check this thread for other possible answers:
http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2004-07/0919.html

This is a simple Python script that does just what you need:
#!/usr/bin/python
import sys
# Clipboard storage
clipboard_file = '/tmp/clipboard.tmp'
if(sys.stdin.isatty()): # Should write clipboard contents out to stdout
with open(clipboard_file, 'r') as c:
sys.stdout.write(c.read())
elif(sys.stdout.isatty()): # Should save stdin to clipboard
with open(clipboard_file, 'w') as c:
c.write(sys.stdin.read())
Save this as an executable somewhere in your path (I saved it to /usr/local/bin/clip. You can pipe in stuff to be saved to your clipboard...
echo "Hello World" | clip
And you can pipe what's in your clipboard to some other program...
clip | cowsay
_____________
< Hello World >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Running it by itself will simply output what's in the clipboard.

I have found a good reference: How to target multiple selections with xclip
In my case, I would like to paste content on the clipboard and also to see what is been pasted there, so I used also the tee command with a file descriptor:
echo "just a test" | tee >(xclip -i -selection clipboard)
>() is a form of process substitution. Bash replaces each with the path to a file descriptor which is connected to the standard input of the program within the parentheses.
The teecommand forks your command allowing you to "pipe its content" and see the result on standard output "stdout".
You can also create aliases to get and write on the clipboard, allowing you to use "pbcopy" and "pbpaste" as if you where on Mac. In my case, as I use Z shell (zsh), I have this in my aliases file:
(( $+commands[xclip] )) && {
alias pbpaste='xclip -i -selection clipboard -o'
alias pbcopy='xclip -selection clipboard'
}
The (( $+command[name] )) in Z shell tests if the command "name" is installed on your system, and then both aliases are grouped with {}. The && is a binary AND; if a then b, hence if you have xclip then the aliases will be set.
echo "another test" | tee >(pbcopy)
To get your clipboard content, just type:
pbpaste | "any-command-you-need-here"

I just searched the same stuff in my KDE environment.
Feel free to use clipcopy and clippaste.
KDE:
> echo "TEST CLIP FROM TERMINAL" | clipcopy
> clippaste
TEST CLIP FROM TERMINAL

xsel -b
Does the job for X Window, and it is mostly already installed.
A look in the man page of xsel is worth the effort.

Copy and paste to clipboard in Windows (Cygwin):
See:
$ clip.exe -?
CLIP
Description:
Redirects output of command line tools to the Windows clipboard.
This text output can then be pasted into other programs.
Parameter List:
/? Displays this help message.
Examples:
DIR | CLIP Places a copy of the current directory
listing into the Windows clipboard.
CLIP < README.TXT Places a copy of the text from readme.txt
on to the Windows clipboard.
Also getclip (it can be used instead of Shift + Ins!) and putclip (echo oaeuoa | putclip.exe to put it into clip) exist.

In Linux this works:
cat filename | xclip

pbcopy is built into OS X:
Copying the content of file .bash_profile:
cat ~/.bash_profile | pbcopy

There are a couple of ways. Some of the ways that have been mentioned include (I think) tmux, Screen, Vim, Emacs, and the shell. I don't know Emacs or Screen, so I'll go over the other three.
Tmux
While not an X selection, tmux has a copy mode accessible via prefix-[ (prefix is Ctrl + B by default). The buffer used for this mode is separate and exclusive to tmux, which opens up quite a few possibilities and makes it more versatile than the X selections in the right situations.
To exit this mode, hit Q; to navigate, use your Vim or Emacs binding (default = Vim), so hjkl for movement, v/V/C-v for character/line/block selection, etc. When you have your selection, hit Enter to copy and exit the mode.
To paste from this buffer, use prefix-].
Shell
Any installation of X11 seems to come with two programs by default: xclip and xsel (kind of like how it also comes with both startx and xinit). Most of the other answers mention xclip, and I really like xsel for its brevity, so I'm going to cover xsel.
From xsel(1x):
Input options \
-a, --append \
append standard input to the selection. Implies -i.
-f, --follow \
append to selection as standard input grows. Implies -i.
-i, --input \
read standard input into the selection.
Output options \
-o, --output \
write the selection to standard output.
Action options \
-c, --clear \
clear the selection. Overrides all input options.
-d, --delete \
Request that the current selection be deleted. This not only clears the selection, but also requests to the program in which the selection resides that the selected contents be deleted. Overrides all input options.
Selection options \
-p, --primary \
operate on the PRIMARY selection (default).
-s, --secondary \
operate on the SECONDARY selection.
-b, --clipboard \
operate on the CLIPBOARD selection.
And that's about all you need to know. p (or nothing) for PRIMARY, s for SECONDARY, b for CLIPBOARD, o for output.
Example: say I want to copy the output of foo from a TTY and paste it to a webpage for a bug report. To do this, it would be ideal to copy to/from the TTY/X session. So the question becomes how do I access the clipboard from the TTY?
For this example, we'll assume the X session is on display :1.
$ foo -v
Error: not a real TTY
details:
blah blah # 0x0000000040abeaf4
blah blah # 0x0000000040abeaf8
blah blah # 0x0000000040abeafc
blah blah # 0x0000000040abeb00
...
$ foo -v | DISPLAY=:1 xsel -b # copies it into clipboard of display :1
Then I can Ctrl + V it into the form as per usual.
Now say that someone on the support site gives me a command to run to fix the problem. It's complicated and long.
$ DISPLAY=:1 xsel -bo
sudo foo --update --clear-cache --source-list="http://foo-software.com/repository/foo/debian/ubuntu/xenial/164914519191464/sources.txt"
$ $(DISPLAY=:1 xsel -bo)
Password for braden:
UPDATING %%%%%%%%%%%%%%%%%%%%%%% 100.00%
Clearing cache...
Fetching sources...
Reticulating splines...
Watering trees...
Climbing mountains...
Looking advanced...
Done.
$ foo
Thank you for your order. A pizza should arrive at your house in the next 20 minutes. Your total is $6.99
Pizza ordering seems like a productive use of the command line.
...moving on.
Vim
If compiled with +clipboard (This is important! Check your vim --version), Vim should have access to the X PRIMARY and CLIPBOARD selections. The two selections are accessible from the * and + registers, respectively, and may be written to and read from at your leisure the same as any other register.
For example:
:%y+ ; copy/yank (y) everything (%) into the CLIPBOARD selection (+)
"+p ; select (") the CLIPBOARD selection (+) and paste/put it
ggVG"+y ; Alternative version of the first example
If your copy of Vim doesn't directly support access to X selections, though, it's not the end of the world. You can just use the xsel technique as described in the last section.
:r ! xsel -bo ; read (r) from the stdout of (!) `xsel -bo`
:w ! xsel -b ; write (w) to the stdin of (!) `xsel -b`
Bind a couple key combos and you should be good.

On Wayland, xcopy doesn't seem to work. Use wl-clipboard instead.
E.g., on Fedora:
sudo dnf install wl-clipboard
tree | wl-copy
wl-paste > file

The Ruby oneliner inspired me to try with Python.
Say we want a command that indents whatever is in the clipboard with four spaces. It is perfect for sharing snippets on Stack Overflow.
$ pbpaste | python -c "import sys
for line in sys.stdin:
print(f' {line}')" | pbcopy
That's not a typo. Python needs newlines to do a for loop. We want to alter the lines in one pass to avoid building up an extra array in memory.
If you don't mind building the extra array try:
$ pbpaste | python -c "import sys; print(''.join([f' {l}' for l in sys.stdin]))" | pbcopy
but honestly awk is better for this than python. I defined this alias in my ~/.bashrc file
alias indent="pbpaste | awk '{print \" \"\$0}' | pbcopy"
Now when I run indent, whatever is in my clipboard is indented.

A few Windows programs I wrote years ago. They allow you dump, push, append and print the clipboard. It works like this:
dumpclip | perl -pe "s/monkey/chimp/g;" | pushclip
It includes source code: cmd_clip.zip

Yesterday I found myself with the question: "How can I share the clipboard between different user sessions?". When switching between sessions with Ctrl + Alt + F7 - Ctrl + Alt + F8, in fact, you can't paste what you copied.
I came up with the following quick & dirty solution, based on a named pipe. It is surely quite bare and raw, but I found it functional:
user1#host:~$ mkfifo /tmp/sharedClip
then in the sending terminal
user1#host:~$ cat > /tmp/sharedClip
last, in the receiving terminal:
user2#host:~$ cat /tmp/sharedClip
Now, you type or paste anything in the first terminal, and (after hitting Return), it will appear immediately in the receiving terminal, from where you can copy and paste again anywhere you like.
Of course this doesn't just strictly take the content from user1's clipboard to make it available in user2's clipboard, but rather it requires an additional pair of Paste & Copy clicks.

From this thread, there is an option which does not require installing any gclip/xclip/xsel third-party software.
A Perl script (since Perl is usually always installed)
use Win32::Clipboard;
print Win32::Clipboard::GetText();

In macOS, use pbpaste.
For example:
Update the clipboard
pbpaste | ruby -ne ' puts "\|" + $_.split( )[1..4].join("\|") ' | pbcopy

A way to paste from the clipboard to a file without any tools except echo.
Escape single quotes in the text you want to paste: replace all occurrences of ' with '\'' and copy the result to clipboard.
Type echo -n '
Press Shift + Insert
Type ' > filename.txt
Press Enter
Basically you're doing this:
echo -n 'copied "text" with '\''single quotes'\'' escaped' > filename.txt
It works even if the copied text has new lines.

For mac you can use this function which uses pbcopy and pbpaste, but a little easier:
Add this to your .bashrc or .zshrc:
clp() {
if [[ -z "$1" ]]
then
# No input - act as paste
pbpaste;
else
# Input exists - act as copy
echo "$1" | pbcopy;
fi
}
To copy use clp "Content" and to paste use clp

If you're like me and run on a Linux server without root privileges and there isn't any xclip or GPM you could workaround this issue by just using a temporary file. For example:
$ echo "Hello, World!" > ~/clip
$ echo `cat ~/clip`
Hello, World!

Related

Copy Terminal Output For GUI Pasting [duplicate]

Is it possible to pipe to/from the clipboard in Bash?
Whether it is piping to/from a device handle or using an auxiliary application, I can't find anything.
For example, if /dev/clip was a device linking to the clipboard we could do:
cat /dev/clip # Dump the contents of the clipboard
cat foo > /dev/clip # Dump the contents of "foo" into the clipboard
There are a wealth of clipboards you could be dealing with. I expect you're probably a Linux user who wants to put stuff in the X Windows primary clipboard. Usually, the clipboard you want to talk to has a utility that lets you talk to it.
In the case of X, there's xclip (and others). xclip -selection c will send data to the clipboard that works with Ctrl + C, Ctrl + V in most applications.
If you're on Mac OS X, there's pbcopy. E.g., cat example.txt | pbcopy
If you're in Linux terminal mode (no X) then look into gpm or Screen which has a clipboard. Try the Screen command readreg.
Under Windows 10+ or Cygwin, use /dev/clipboard or clip.
Make sure you are using alias xclip="xclip -selection c"
or else you won't be able to paste using Ctrl+v.
Example:
After running echo -n test | xclip, Ctrl+v will paste test
Install
# You can install xclip using `apt-get`
apt-get install xclip
# or `pacman`
pacman -S xclip
# or `dnf`
dnf install xclip
If you do not have access to apt-get nor pacman, nor dnf, the sources are available on sourceforge.
Set-up
Bash
In ~/.bash_aliases, add:
alias setclip="xclip -selection c"
alias getclip="xclip -selection c -o"
Do not forget to load your new configuration using . ~/.bash_aliases or by restarting your profile.
Fish
In ~/.config/fish/config.fish, add:
abbr setclip "xclip -selection c"
abbr getclip "xclip -selection c -o"
Do not forget to restart your fish instance by restarting your terminal for changes to apply.
Usage
You can now use setclip and getclip, e.g:
$ echo foo | setclip
$ getclip
foo
On macOS, use the built-in pbcopy and pbpaste commands.
For example, if you run
cat ~/.bashrc | pbcopy
the contents of the ~/.bashrc file will be available for pasting with the Cmd + V shortcut.
To save the current clipboard to a file, redirect the output pbpaste to a file:
pbpaste > my_clipboard.txt
2018 answer
Use clipboard-cli. It works with macOS, Windows, Linux, OpenBSD, FreeBSD, and Android without any real issues.
Install it with:
npm install -g clipboard-cli
Then you can do:
echo foo | clipboard
If you want, you can alias to cb by putting the following in your .bashrc, .bash_profile, or .zshrc:
alias cb=clipboard
xsel on Debian/Ubuntu/Mint
# append to clipboard:
cat 'the file with content' | xsel -ab
# or type in the happy face :) and ...
echo 'the happy face :) and content' | xsel -ib
# show clipboard
xsel -ob
# Get more info:
man xsel
Install
sudo apt-get install xsel
Try
xclip
xclip - command line interface to X selections (clipboard)
man
On the Windows Subsystem for Linux (WSL) you can copy to the clipboard with clip.exe:
cat file | clip.exe
Keep in mind to use the | pipe command. And not a > command, since that will not work.
Install the xcopy utility and when you're in the Terminal, input:
Copy
Thing_you_want_to_copy | xclip -selection c
Paste
myvariable=$(xclip -selection clipboard -o)
I noticed a lot of answers recommended pbpaste and pbcopy. If you're into those utilities, but for some reason they are not available in your repository, you can always make an alias for the xcopy commands and call them pbpaste and pbcopy.
alias pbcopy="xclip -selection c"
alias pbpaste="xclip -selection clipboard -o"
So then it would look like this:
Thing_you_want_to_copy | pbcopy
myvariable=$(pbpaste)
An answer located in one of the comments written by a user called doug work for me. Since I found it so helpful, I decided to restate in an answer.
Here is a ready-to-use Bash script for reading the clipboard which works on multiple platforms.
Please edit the script here if you add functionality (e.g., more platforms).
#!/bin/bash
# WF 2013-10-04
#
# Multi-platform clipboard read access
#
# Supports
# Mac OS X
# Git shell / Cygwin (Windows)
# Linux (e.g., Ubuntu)
#
# Display an error
#
error() {
echo "error: $1" 1>&2
exit 1
}
#
# getClipboard
#
function getClipboard() {
os=`uname`
case $os in
# Git Bash (Windows)
MINGW32_NT-6.1)
cat /dev/clipboard;;
# Mac OS X
Darwin*)
pbpaste;;
# Linux
Linux*)
# Works only for the X clipboard - a check that X is running might be due
xclip -o;;
*)
error "unsupported os $os";;
esac
}
tmp=/tmp/clipboard$$
getClipboard >$tmp
cat $tmp
# Comment out for debugging
rm $tmp
For Mac only:
echo "Hello World" | pbcopy
pbpaste
These are located /usr/bin/pbcopy and /usr/bin/pbpaste.
On Windows (with Cygwin) try
cat /dev/clipboard or echo "foo" > /dev/clipboard as mentioned in this article.
There are different clipboards in Linux; the X server has one, the window manager might have another one, etc. There is no standard device.
Oh, yes, on CLI, the screen program has its own clipboard as well, as do some other applications like Emacs and vi.
In X, you can use xclip.
You can check this thread for other possible answers:
http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2004-07/0919.html
This is a simple Python script that does just what you need:
#!/usr/bin/python
import sys
# Clipboard storage
clipboard_file = '/tmp/clipboard.tmp'
if(sys.stdin.isatty()): # Should write clipboard contents out to stdout
with open(clipboard_file, 'r') as c:
sys.stdout.write(c.read())
elif(sys.stdout.isatty()): # Should save stdin to clipboard
with open(clipboard_file, 'w') as c:
c.write(sys.stdin.read())
Save this as an executable somewhere in your path (I saved it to /usr/local/bin/clip. You can pipe in stuff to be saved to your clipboard...
echo "Hello World" | clip
And you can pipe what's in your clipboard to some other program...
clip | cowsay
_____________
< Hello World >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Running it by itself will simply output what's in the clipboard.
I have found a good reference: How to target multiple selections with xclip
In my case, I would like to paste content on the clipboard and also to see what is been pasted there, so I used also the tee command with a file descriptor:
echo "just a test" | tee >(xclip -i -selection clipboard)
>() is a form of process substitution. Bash replaces each with the path to a file descriptor which is connected to the standard input of the program within the parentheses.
The teecommand forks your command allowing you to "pipe its content" and see the result on standard output "stdout".
You can also create aliases to get and write on the clipboard, allowing you to use "pbcopy" and "pbpaste" as if you where on Mac. In my case, as I use Z shell (zsh), I have this in my aliases file:
(( $+commands[xclip] )) && {
alias pbpaste='xclip -i -selection clipboard -o'
alias pbcopy='xclip -selection clipboard'
}
The (( $+command[name] )) in Z shell tests if the command "name" is installed on your system, and then both aliases are grouped with {}. The && is a binary AND; if a then b, hence if you have xclip then the aliases will be set.
echo "another test" | tee >(pbcopy)
To get your clipboard content, just type:
pbpaste | "any-command-you-need-here"
I just searched the same stuff in my KDE environment.
Feel free to use clipcopy and clippaste.
KDE:
> echo "TEST CLIP FROM TERMINAL" | clipcopy
> clippaste
TEST CLIP FROM TERMINAL
xsel -b
Does the job for X Window, and it is mostly already installed.
A look in the man page of xsel is worth the effort.
Copy and paste to clipboard in Windows (Cygwin):
See:
$ clip.exe -?
CLIP
Description:
Redirects output of command line tools to the Windows clipboard.
This text output can then be pasted into other programs.
Parameter List:
/? Displays this help message.
Examples:
DIR | CLIP Places a copy of the current directory
listing into the Windows clipboard.
CLIP < README.TXT Places a copy of the text from readme.txt
on to the Windows clipboard.
Also getclip (it can be used instead of Shift + Ins!) and putclip (echo oaeuoa | putclip.exe to put it into clip) exist.
In Linux this works:
cat filename | xclip
pbcopy is built into OS X:
Copying the content of file .bash_profile:
cat ~/.bash_profile | pbcopy
There are a couple of ways. Some of the ways that have been mentioned include (I think) tmux, Screen, Vim, Emacs, and the shell. I don't know Emacs or Screen, so I'll go over the other three.
Tmux
While not an X selection, tmux has a copy mode accessible via prefix-[ (prefix is Ctrl + B by default). The buffer used for this mode is separate and exclusive to tmux, which opens up quite a few possibilities and makes it more versatile than the X selections in the right situations.
To exit this mode, hit Q; to navigate, use your Vim or Emacs binding (default = Vim), so hjkl for movement, v/V/C-v for character/line/block selection, etc. When you have your selection, hit Enter to copy and exit the mode.
To paste from this buffer, use prefix-].
Shell
Any installation of X11 seems to come with two programs by default: xclip and xsel (kind of like how it also comes with both startx and xinit). Most of the other answers mention xclip, and I really like xsel for its brevity, so I'm going to cover xsel.
From xsel(1x):
Input options \
-a, --append \
append standard input to the selection. Implies -i.
-f, --follow \
append to selection as standard input grows. Implies -i.
-i, --input \
read standard input into the selection.
Output options \
-o, --output \
write the selection to standard output.
Action options \
-c, --clear \
clear the selection. Overrides all input options.
-d, --delete \
Request that the current selection be deleted. This not only clears the selection, but also requests to the program in which the selection resides that the selected contents be deleted. Overrides all input options.
Selection options \
-p, --primary \
operate on the PRIMARY selection (default).
-s, --secondary \
operate on the SECONDARY selection.
-b, --clipboard \
operate on the CLIPBOARD selection.
And that's about all you need to know. p (or nothing) for PRIMARY, s for SECONDARY, b for CLIPBOARD, o for output.
Example: say I want to copy the output of foo from a TTY and paste it to a webpage for a bug report. To do this, it would be ideal to copy to/from the TTY/X session. So the question becomes how do I access the clipboard from the TTY?
For this example, we'll assume the X session is on display :1.
$ foo -v
Error: not a real TTY
details:
blah blah # 0x0000000040abeaf4
blah blah # 0x0000000040abeaf8
blah blah # 0x0000000040abeafc
blah blah # 0x0000000040abeb00
...
$ foo -v | DISPLAY=:1 xsel -b # copies it into clipboard of display :1
Then I can Ctrl + V it into the form as per usual.
Now say that someone on the support site gives me a command to run to fix the problem. It's complicated and long.
$ DISPLAY=:1 xsel -bo
sudo foo --update --clear-cache --source-list="http://foo-software.com/repository/foo/debian/ubuntu/xenial/164914519191464/sources.txt"
$ $(DISPLAY=:1 xsel -bo)
Password for braden:
UPDATING %%%%%%%%%%%%%%%%%%%%%%% 100.00%
Clearing cache...
Fetching sources...
Reticulating splines...
Watering trees...
Climbing mountains...
Looking advanced...
Done.
$ foo
Thank you for your order. A pizza should arrive at your house in the next 20 minutes. Your total is $6.99
Pizza ordering seems like a productive use of the command line.
...moving on.
Vim
If compiled with +clipboard (This is important! Check your vim --version), Vim should have access to the X PRIMARY and CLIPBOARD selections. The two selections are accessible from the * and + registers, respectively, and may be written to and read from at your leisure the same as any other register.
For example:
:%y+ ; copy/yank (y) everything (%) into the CLIPBOARD selection (+)
"+p ; select (") the CLIPBOARD selection (+) and paste/put it
ggVG"+y ; Alternative version of the first example
If your copy of Vim doesn't directly support access to X selections, though, it's not the end of the world. You can just use the xsel technique as described in the last section.
:r ! xsel -bo ; read (r) from the stdout of (!) `xsel -bo`
:w ! xsel -b ; write (w) to the stdin of (!) `xsel -b`
Bind a couple key combos and you should be good.
On Wayland, xcopy doesn't seem to work. Use wl-clipboard instead.
E.g., on Fedora:
sudo dnf install wl-clipboard
tree | wl-copy
wl-paste > file
The Ruby oneliner inspired me to try with Python.
Say we want a command that indents whatever is in the clipboard with four spaces. It is perfect for sharing snippets on Stack Overflow.
$ pbpaste | python -c "import sys
for line in sys.stdin:
print(f' {line}')" | pbcopy
That's not a typo. Python needs newlines to do a for loop. We want to alter the lines in one pass to avoid building up an extra array in memory.
If you don't mind building the extra array try:
$ pbpaste | python -c "import sys; print(''.join([f' {l}' for l in sys.stdin]))" | pbcopy
but honestly awk is better for this than python. I defined this alias in my ~/.bashrc file
alias indent="pbpaste | awk '{print \" \"\$0}' | pbcopy"
Now when I run indent, whatever is in my clipboard is indented.
A few Windows programs I wrote years ago. They allow you dump, push, append and print the clipboard. It works like this:
dumpclip | perl -pe "s/monkey/chimp/g;" | pushclip
It includes source code: cmd_clip.zip
Yesterday I found myself with the question: "How can I share the clipboard between different user sessions?". When switching between sessions with Ctrl + Alt + F7 - Ctrl + Alt + F8, in fact, you can't paste what you copied.
I came up with the following quick & dirty solution, based on a named pipe. It is surely quite bare and raw, but I found it functional:
user1#host:~$ mkfifo /tmp/sharedClip
then in the sending terminal
user1#host:~$ cat > /tmp/sharedClip
last, in the receiving terminal:
user2#host:~$ cat /tmp/sharedClip
Now, you type or paste anything in the first terminal, and (after hitting Return), it will appear immediately in the receiving terminal, from where you can copy and paste again anywhere you like.
Of course this doesn't just strictly take the content from user1's clipboard to make it available in user2's clipboard, but rather it requires an additional pair of Paste & Copy clicks.
From this thread, there is an option which does not require installing any gclip/xclip/xsel third-party software.
A Perl script (since Perl is usually always installed)
use Win32::Clipboard;
print Win32::Clipboard::GetText();
In macOS, use pbpaste.
For example:
Update the clipboard
pbpaste | ruby -ne ' puts "\|" + $_.split( )[1..4].join("\|") ' | pbcopy
A way to paste from the clipboard to a file without any tools except echo.
Escape single quotes in the text you want to paste: replace all occurrences of ' with '\'' and copy the result to clipboard.
Type echo -n '
Press Shift + Insert
Type ' > filename.txt
Press Enter
Basically you're doing this:
echo -n 'copied "text" with '\''single quotes'\'' escaped' > filename.txt
It works even if the copied text has new lines.
For mac you can use this function which uses pbcopy and pbpaste, but a little easier:
Add this to your .bashrc or .zshrc:
clp() {
if [[ -z "$1" ]]
then
# No input - act as paste
pbpaste;
else
# Input exists - act as copy
echo "$1" | pbcopy;
fi
}
To copy use clp "Content" and to paste use clp
If you're like me and run on a Linux server without root privileges and there isn't any xclip or GPM you could workaround this issue by just using a temporary file. For example:
$ echo "Hello, World!" > ~/clip
$ echo `cat ~/clip`
Hello, World!

How to fzf recent files of vim/nvim, not inside vim but from terminal

I know how to fzf.vim, but I'd like to open from terminal.
Grepping history or viminfo may be achieve thst, but I wonder if there is any smart way.
This is how you can save the list of recent files from vim to a file:
vim -c "call append(0, v:oldfiles)" -c "write vim-oldfiles.tmp" -c exit
Put v:oldfiles (the list of recent files saved in ~/.viminfo) into the first (new and empty at the start) buffer, write the buffer to a file, exit.
Now you can pass the content of file to fzf.
Not exact solution. But you could open a terminal buffer on the lower part of your vim edit like an IDE and use your terminal fzf
However, not sure if this will let you open a file in a new vim tab
I have an zsh autoloaded function called old:
function old(){
vim -c 'redir >> /tmp/oldfiles.txt | silent oldfiles | redir end | q'
sed -i '/NvimTree$/d' /tmp/oldfiles.txt
local fname
fname=$(awk '/home/ && !/man:/ {print $2}' /tmp/oldfiles.txt | fzf) || return
vim "$fname"
\rm /tmp/oldfiles.txt
}
If you're having trouble executing vim on files that have ~ in their path (vim open a new blank file instead of the desired file) because fzf and vim don't expand tilde (~), here's how I do it:
export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS"
--bind 'ctrl-e:execute(vim -c \"execute \\\"edit\\\" expand({})\" >/dev/tty)'
"
It's trial and error, based on this.
Combining some of the other answers, here's a version that does not need a temporary file and writes to stdout (so you can pipe this into another command, or capture the output using $(...)).
vim -e -c "redir >> /dev/fd/100 | for f in v:oldfiles | silent echo substitute(f, \"^\\\\~\", \$HOME, \"g\") | endfor | redir end | q" 100>&1 &>/dev/null
This solution combines elements from other solutions, but with some improvements:
It uses some shell redirection to duplicate stdout to some free fd (100>&1) and then uses /dev/fd/100 to force writing output there. This ensures that vim actually writes to stdout rather than the terminal. Note that this can also be made to work using /dev/fd/1 (but only when omitting redir end for some reason), but then we cannot apply the next point.
It redirects stdout (and for good measure) also stderr to /dev/null, to prevent vim writing some terminal escape codes to stdout on startup, so using a different fd ensures clean output.
It uses vim in "ex" mode (vim -e) to suppress the "Vim: Warning: Output is not to a terminal" output and accompanying delay. [source]
It uses a for-loop to iterate over v:oldfiles to output just the filenames (the oldfiles command used by https://stackoverflow.com/a/70749181/740048 adds line numbers).
It uses a substitute to expand ~ in the filenames returned by vim (making the returned filenames easier to proces. Normally, shells like bash expand ~ in arguments passed to commands, but this happens only for tildes in the command typed, not tildes that result from variables or command substitution. To prevent having to rely on unsafe eval'ing later, better to expand (just) the tildes beforehand.
I also tried using the append / write combo from https://stackoverflow.com/a/60018642/740048, which worked with the /dev/fd/100 trick, but then ended up putting /dev/fd/100 in the list of oldfiles, so I did not use that approach.

Shell Script Edit Files Line

I am not that good on linux shell script and I need little help.
I want to edit a file via script (finding the line and edit).
The Original line is:
# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=< hostname >"
I want to uncomment and replaye hostname with 127.0.0.1
JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=127.0.0.1"
You can refer to the set command, change the filename with the name you are working at,
sed -i 's## JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=< hostname >"#JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=127.0.0.1"#' filename
Fine answers, but they don't do anything by way of TEACHING the gentleman how and why it works.
If you were using the mundane text editor, ed, you would use three commands after invoking the command "ed filename":
s/^# //
s/< hostname>/127.0.0.1/
w
So, you can use a pipe to submit those commands directly to ed, specifying "-" as its first argument so that it doesn't bother you by reporting character counts upon reading in and writing out the file:
( echo 's/^# //'; echo 's//127.0.0.1/'; echo w ) | ed - filename
You don't need to echo 'q' also because ed will automatically quit when it runs out of input or encounters "end of file" (you can simulate this on the keyboard by just hitting the CTRL-D key rather than actually typing q ).
Here's one way to do it:
sed -i -e 's/# \(JVM_OPTS=.*=\).*/\1127.0.0.1"/' path/to/file
That is, replace the line with the text captured within the group \(JVM_OPTS=.*=\), so everything from JVM_OPTS= until another = sign, and append 127.0.0.1" to the end.
If there might be other lines in the file starting with # JVM_OPTS=,
then you could make the pattern matching more strict, for example:
sed -i -e 's/# \(JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=\).*/\1127.0.0.1"/' path/to/file

Using 'diff' (or anything else) to get character-level diff between text files

I'd like to use 'diff' to get a both line difference between and character difference.
For example, consider:
File 1
abcde
abc
abcccd
File 2
abcde
ab
abccc
Using diff -u I get:
## -1,3 +1,3 ##
abcde
-abc
-abcccd
\ No newline at end of file
+ab
+abccc
\ No newline at end of file
However, it only shows me that were changes in these lines. What I'd like to see is something like:
## -1,3 +1,3 ##
abcde
-ab<ins>c</ins>
-abccc<ins>d</ins>
\ No newline at end of file
+ab
+abccc
\ No newline at end of file
You get my drift.
Now, I know I can use other engines to mark/check the difference on a specific line. But I'd rather use one tool that does all of it.
Git has a word diff, and defining all characters as words effectively gives you a character diff. However, newline changes are ignored.
Example
Create a repository like this:
mkdir chardifftest
cd chardifftest
git init
echo -e 'foobarbaz\ncatdog\nfox' > file
git add -A; git commit -m 1
echo -e 'fuobArbas\ncat\ndogfox' > file
git add -A; git commit -m 2
Now, do git diff --word-diff=color --word-diff-regex=. master^ master and you'll get:
Note how both additions and deletions are recognized at the character level, while both additions and deletions of newlines are ignored.
You may also want to try one of these:
git diff --word-diff=plain --word-diff-regex=. master^ master
git diff --word-diff=porcelain --word-diff-regex=. master^ master
You can use:
diff -u f1 f2 |colordiff |diff-highlight
colordiff is a Ubuntu package. You can install it using sudo apt-get install colordiff.
diff-highlight is from git (since version 2.9). It is located in /usr/share/doc/git/contrib/diff-highlight/diff-highlight. You can put it somewhere in your $PATH.
Python's difflib is ace if you want to do this programmatically. For interactive use, I use vim's diff mode (easy enough to use: just invoke vim with vimdiff a b). I also occaisionally use Beyond Compare, which does pretty much everything you could hope for from a diff tool.
I haven't see any command line tool which does this usefully, but as Will notes, the difflib example code might help.
You can use the cmp command in Solaris:
cmp
Compare two files, and if they differ, tells the first byte and line number where they differ.
Python has convenient library named difflib which might help answer your question.
Below are two oneliners using difflib for different python versions.
python3 -c 'import difflib, sys; \
print("".join( \
difflib.ndiff( \
open(sys.argv[1]).readlines(),open(sys.argv[2]).readlines())))'
python2 -c 'import difflib, sys; \
print "".join( \
difflib.ndiff( \
open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines()))'
These might come in handy as a shell alias which is easier to move around with your .${SHELL_NAME}rc.
$ alias char_diff="python2 -c 'import difflib, sys; print \"\".join(difflib.ndiff(open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines()))'"
$ char_diff old_file new_file
And more readable version to put in a standalone file.
#!/usr/bin/env python2
from __future__ import with_statement
import difflib
import sys
with open(sys.argv[1]) as old_f, open(sys.argv[2]) as new_f:
old_lines, new_lines = old_f.readlines(), new_f.readlines()
diff = difflib.ndiff(old_lines, new_lines)
print ''.join(diff)
Coloured, character-level diff ouput
Here's what you can do with the the below script and diff-highlight (which is part of git):
#!/bin/sh -eu
# Use diff-highlight to show word-level differences
diff -U3 --minimal "$#" |
sed 's/^-/\x1b[1;31m-/;s/^+/\x1b[1;32m+/;s/^#/\x1b[1;34m#/;s/$/\x1b[0m/' |
diff-highlight
(Credit to #retracile's answer for the sed highlighting)
cmp -l file1 file2 | wc
Worked well for me. The leftmost number of the result indicates the number of characters that differ.
I also wrote my own script to solve this problem using the Longest common subsequence algorithm.
It is executed as such
JLDiff.py a.txt b.txt out.html
The result is in html with red and green coloring. Larger files do exponentually take a longer amount of time to process but this does a true character by character comparison without checking line by line first.
Python's difflib can do this.
The documentation includes an example command-line program for you.
The exact format is not as you specified, but it would be straightforward to either parse the ndiff-style output or to modify the example program to generate your notation.
As one comment to main answer said you don't have to commit to use git diff:
git diff --word-diff=color --word-diff-regex=. file1 file2
green would be the character that is added by the second file.
red would be the character that is added by the first file.
Here is an online text comparison tool:
http://text-compare.com/
It can highlight every single char that is different and continues compare the rest.
ccdiff is a convenient dedicated tool for the task. Here is what your example looks like with it:
By default, it highlights the differences in color, but it can be used in a console without color support too.
The package is included in the main repository of Debian:
ccdiff is a colored diff that also colors inside changed lines.
All command-line tools that show the difference between two files fall short in showing minor changes visuably useful. ccdiff tries to give the look and feel of diff --color or colordiff, but extending the display of colored output from colored deleted and added lines to colors for deleted and addedd characters within the changed lines.
Not a complete answer, but if cmp -l's output is not clear enough, you can use:
sed 's/\(.\)/\1\n/g' file1 > file1.vertical
sed 's/\(.\)/\1\n/g' file2 > file2.vertical
diff file1.vertical file2.vertical
If you keep your files in Git, you can diff between versions with the diff-highlight script, which will show different lines, with differences highlighted.
Unfortunately it only works when the number of lines removed matches the number of lines added - there is stub code for when lines don't match, so presumably this could be fixed in the future.
I think the simpler solution is always a good solution.
In my case, the below code helps me a lot. I hope it helps
anybody else.
#!/bin/env python
def readfile( fileName ):
f = open( fileName )
c = f.read()
f.close()
return c
def diff( s1, s2 ):
counter=0
for ch1, ch2 in zip( s1, s2 ):
if not ch1 == ch2:
break
counter+=1
return counter < len( s1 ) and counter or -1
import sys
f1 = readfile( sys.argv[1] )
f2 = readfile( sys.argv[2] )
pos = diff( f1, f2 )
end = pos+200
if pos >= 0:
print "Different at:", pos
print ">", f1[pos:end]
print "<", f2[pos:end]
You can compare two files with the following syntax at your favorite terminal:
$ ./diff.py fileNumber1 fileNumber2
Most of these answers mention using of diff-highlight, a Perl module. But I didn't want to figure out how to install a Perl module. So I made a few minor changes to it to be a self-contained Perl script.
You can install it using:
▶ curl -o /usr/local/bin/DiffHighlight.pl \
https://raw.githubusercontent.com/alexharv074/scripts/master/DiffHighlight.pl
And the usage (if you have the Ubuntu colordiff mentioned in zhanxw's answer):
▶ diff -u f1 f2 | colordiff | DiffHighlight.pl
And the usage (if you don't):
▶ diff -u f1 f2 | DiffHighlight.pl

How do I change bash history completion to complete what's already on the line?

I found a command a couple of months ago that made my bash history auto-complete on what's already on the line when pressing the up arrow:
$ vim fi
Press ↑
$ vim file.py
I'd like to set this up on my new computer, because it saves a lot of time when keeping a big history. The problem is that I can't for the life of me remember where it was mentioned and reading through endless bash references and tutorials unfortunately didn't help either.
Does anybody know the command?
Probably something like
# ~/.inputrc
"\e[A": history-search-backward
"\e[B": history-search-forward
or equivalently,
# ~/.bashrc
if [[ $- == *i* ]]
then
bind '"\e[A": history-search-backward'
bind '"\e[B": history-search-forward'
fi
(the if statement checks for interactive mode)
Normally, Up and Down are bound to the Readline functions previous-history and next-history respectively. I prefer to bind PgUp/PgDn to these functions, instead of displacing the normal operation of Up/Down.
# ~/.inputrc
"\e[5~": history-search-backward
"\e[6~": history-search-forward
After you modify ~/.inputrc, restart your shell or use Ctrl+X, Ctrl+R to tell it to re-read ~/.inputrc.
By the way, if you're looking for relevant documentation:
Bash uses The GNU Readline Library for the shell prompt and history.
Update .inputrc with the following:
"\C-[OA": history-search-backward
"\C-[[A": history-search-backward
"\C-[OB": history-search-forward
"\C-[[B": history-search-forward
If set enable-keypad on is in your ~/.inputrc as some st (suckless simple terminal) users might, be aware that the arrows keys are in keypad mode. Ubuntu ships with this useful /usr/share/doc/bash/inputrc.arrows:
# This file controls the behaviour of line input editing for
# programs that use the Gnu Readline library.
#
# Arrow keys in keypad mode
#
"\C-[OD" backward-char
"\C-[OC" forward-char
"\C-[OA" previous-history
"\C-[OB" next-history
#
# Arrow keys in ANSI mode
#
"\C-[[D" backward-char
"\C-[[C" forward-char
"\C-[[A" previous-history
"\C-[[B" next-history
#
# Arrow keys in 8 bit keypad mode
#
"\C-M-OD" backward-char
"\C-M-OC" forward-char
"\C-M-OA" previous-history
"\C-M-OB" next-history
#
# Arrow keys in 8 bit ANSI mode
#
"\C-M-[D" backward-char
"\C-M-[C" forward-char
"\C-M-[A" previous-history
"\C-M-[B" next-history
So I'm not sure if you'll need all, but it might not hurt to have in your ~/.inputrc:
# Arrow keys in keypad mode
"\C-[OA": history-search-backward
"\C-[OB": history-search-forward
"\C-[OC": forward-char
"\C-[OD": backward-char
# Arrow keys in ANSI mode
"\C-[[A": history-search-backward
"\C-[[B": history-search-forward
"\C-[[C": forward-char
"\C-[[D": backward-char
This is also on the same topic: My cursor keys do not work and also this xterm: special keys
With ohmyzsh, use this in your .zshrc :
bindkey '\e[A' history-search-backward
bindkey '\e[B' history-search-forward
To reload, source ~/.zshrc or relaunch terminal.
Source: https://superuser.com/a/418299/71680
You may need to enabled bash completion.
Check
/etc/profile
/etc/bash.bashrc
~/.bashrc
to see if any of the above files source /etc/bash_completion. i.e.
. /etc/bash_completion
If /etc/bash___completion is not sourced by any of the above files you will need to add it to one of them.
If you want all bash users on your machine to have bash completion, source /etc/bash_completion from /etc/bash.bashrc.
If it's just you who wants bash completion, source /etc/bash_completion from your ~/.bashrc.

Resources