I don't know of a tool that does exactly what you want. That doesn't mean it doesn't exist, but it does mean that it isn't something you can expect to find on a typical Linux desktop.
Copy-pasting a single file with ordinary household tools
If you're willing to change the requirements slightly, so that it isn't exactly the copy-cut-paste model, things can be simpler. One thing the copy-cut-paste model does which complicates the implementation, and is usually counter-intuitive for files anyway, is to take the cut-vs-copy decision at the point of origin. For files, it usually makes more sense to select at the point of origin, and copy or move at the point of destination. If you take this approach, the point of origin only needs to copy a list of file names, and not the decision to move or copy.
Copying a file name to the clipboard is fairly easy with common tools: xsel
or xclip
on X11, pbcopy
and pbpaste
on macOS. See Copy the contents of a file into the clipboard without displaying its contents and How to read over 4k input without new lines on a terminal?. xsel
and xclip
are usually not installed by default, but they're usually available as packages. I'll use xsel
in my examples because it's shorter to type, the other tools are similar. xsel
is actually buggy with large inputs, but this is not a problem with typical file names.
The following code examples assume that file names don't end in newline characters.
With zsh and xsel, here's a copy-paste example for a single file or directory:
/some/where% xsel <<<$PWD/myfile
/else/where% cp `xsel` .
With bash or ksh you need a few double quotes.
/some/where$ xsel <<<"$PWD/myfile"
/else/where$ cp -p "`xsel`" .
Note that pasting directly into a command line does not work if the file name contains shell special characters.
Dealing with multiple files
The easiest way to deal with multiple files is not to deal with multiple files. If you want to copy multiple files, copy the (name of the) destination directory from the destination terminal, and paste it into the source terminal.
/else/where$ xsel <<<"$PWD"
/some/where$ cp -Rp file1 file2 *.more.files "`xsel`"
I have a script called cfn
(copy file name) which essentially copies its argument with $PWD/
prepended to the clipboard, but adds a bit of robustness: it supports multiple arguments, it copies to both the X selection and the clipboard, it works with both absolute and relative file names, it has options to support Windows paths. It could be improved to use null separators, and then it would support newlines in file names.
#! /bin/sh
# Copy file name
if [ "$#" -eq 0 ] || [ "$1" = "--help" ]; then
cat <<EOF
Usage: $0 [OPTION]... FILENAME [...]
Copy FILENAME to both the X clipboard and the primary selection.
If FILENAME is relative, prepent $PWD.
Multiple FILENAMEs are separated by newlines, but no newline is added at the
end.
-F Do not add a newline after the last file name (default)
-f Do add a newline after the last file name
-p PREFIX Prefix to use instead of $PWD
-r ROOT Prefix to use before ROOT
-s STRING Separator to use instead of a newline
-u Use slash as the path separator (default)
-w Use backslash instead of slash as the path separator
EOF
exit
fi
set -e -f
append=
cwd="$PWD/"
explicit_cwd=
names=
nl='
'
root=
sep='/'
change_separator () {
if [ -z "$1" ]; then
eval "$var="
return
fi
IFS=/
var=$1
eval "set $$var; $var=$1"
shift
if [ "$1" != "" ]; then
set "$@" ""
fi
while [ "$#" -ne 0 ]; do
eval "$var=$$var$sep$1"
shift
done
}
while getopts Ffuwp:r:s: OPTLET; do
case "$OPTLET" in
F) append=;;
f) append=1;;
p) cwd="$OPTARG"; explicit_cwd=1;;
r) root="$OPTARG";;
s) nl="$OPTARG";;
u) sep="/";;
w) sep="\";;
*) echo 1>&2 "$0: unknown option: -$OPTLET"; exit 3;;
esac
done
shift "$((OPTIND-1))"
if [ -z "$explicit_cwd" ] && [ "$sep" != "/" ]; then
change_separator cwd
fi
for x do
case $x in
.) x=${cwd%"$sep"};;
[!/])
if [ "$sep" != "/" ]; then
change_separator x
fi
x="$cwd$x";;
)
if [ "$sep" != "/" ]; then
change_separator x
fi;;
esac
names="$names$root$x$nl"
done
if [ -z "$append" ]; then
names=${names%"$nl"}
fi
printf %s "$names" | xsel
printf %s "$names" | xsel -b
I don't have a corresponding paste script; here's how to paste multiple files (with newline-separated names) in zsh.
/else/where% cp -p ${(f)$(xsel)} .
In bash:
/else/where$ readarray -t a < <(xsel) && cp -p "${a[@]}" .