如果我在不同的工作目录中有两个终端,并且我想将文件从一个终端的 PWD 移动到另一个终端的 PWD 而不使用mv
(因为mv
需要我至少键入其中一个目录)
我们可以通过将它们实现为 bash 脚本来实现非常简单的“剪切”和“粘贴”功能:
# cut (pseudocode)
fname=<target>
mv <target> /tmp/the-cut-file
# paste
mv /tmp/the-cut-file ./$fname
我想知道是否存在处理此功能的标准工具,因此我不必推出自己的工具(并处理边缘情况,维护它,而不是获取命令行自动完成...等)
答案1
我不知道有哪个工具可以完全满足您的要求。这并不意味着它不存在,但它确实意味着您不可能在典型的 Linux 桌面上找到它。
使用普通家用工具复制粘贴单个文件
如果您愿意稍微更改需求,使其不完全是复制-剪切-粘贴模型,那么事情会变得更简单。复制-剪切-粘贴模型所做的一件事是在源点做出剪切与复制的决定,这使得实现变得复杂,而且对于文件来说通常是违反直觉的。对于文件来说,在源点进行选择并在目标点进行复制或移动通常更有意义。如果采用这种方法,源点只需要复制文件名列表,而不决定移动或复制。
使用常用工具将文件名复制到剪贴板相当容易:xsel
或者xclip
在 X11pbcopy
和pbpaste
macOS 上。看将文件的内容复制到剪贴板而不显示其内容和如何在终端上读取超过 4k 的输入而不换行?。xsel
通常xclip
默认情况下不会安装,但它们通常作为软件包提供。我将xsel
在我的示例中使用它,因为它的打字时间更短,其他工具类似。xsel
对于大输入实际上是有问题的,但这对于典型的文件名来说不是问题。
以下代码示例假设文件名不以换行符结尾。
对于 zsh 和 xsel,以下是单个文件或目录的复制粘贴示例:
/some/where% xsel <<<$PWD/myfile
/else/where% cp `xsel` .
对于 bash 或 ksh,您需要一些双引号。
/some/where$ xsel <<<"$PWD/myfile"
/else/where$ cp -p "`xsel`" .
请注意,如果文件名包含 shell 特殊字符,则直接粘贴到命令行中不起作用。
处理多个文件
处理多个文件最简单的方法就是不处理多个文件。如果要复制多个文件,请从目标终端复制目标目录(的名称),并将其粘贴到源终端中。
/else/where$ xsel <<<"$PWD"
/some/where$ cp -Rp file1 file2 *.more.files "`xsel`"
我有一个名为cfn
(C奥皮F伊莱name) 本质上是将其参数复制$PWD/
到剪贴板,但增加了一点鲁棒性:它支持多个参数,它复制到 X 选择和剪贴板,它适用于绝对和相对文件名,它有以下选项支持Windows路径。可以改进为使用空分隔符,然后它将支持文件名中的换行符。
#! /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
我没有相应的粘贴脚本;以下是如何在 zsh 中粘贴多个文件(名称以换行符分隔)。
/else/where% cp -p ${(f)$(xsel)} .
在bash中:
/else/where$ readarray -t a < <(xsel) && cp -p "${a[@]}" .