问题描述
想象一下,我的终端中有这条线:
youtube-dl --get-thumbnail --extract-audio --audio-format mp3 https://www.youtube.com/watch?v=
测试后,我想将上面的这一行复制到我的剪贴板并将其粘贴到某个脚本文件中。不是命令的输出。但是,在不使用鼠标的情况下执行此操作。我喜欢只把手放在键盘上。我认为这样更快,做一些编码:)
最佳思路
我的答案提供了三种不同语法的简单命令,它们都同样有效,但一种比第二种更短更容易输入。第三种变体是 so-called 别名,这意味着您可以为命令指定一个自定义名称并通过执行它来调用它,而无需记住复杂的内容。
准备:
首先,安装包 xsel
,它允许您从终端访问 X 剪贴板:
sudo apt-get install xsel
命令变体 1(短):
之后,您可以键入以下行将上一个命令复制到剪贴板:
xsel -ib <<<!!:q
如果要复制第二个最新的命令,请将 !!
替换为 !-2
,第三个最新的使用 !-3
等等。
为了解释您正在运行的内容,这里对命令进行了简短的分解:
-
xsel
是用于访问 X 剪贴板的 命令行 工具。有关更多信息,请在线阅读其手册页或运行man xsel
。-
-i
参数告诉xsel
从标准输入读取(通常这意味着键盘输入,但我们将在这里重定向一些东西) -
-b
参数指定使用剪贴板而不是 X 的 “primary” 或 “secondary” 选择。
-
-
<<<
是一种特殊的 Bash 语法,称为 “Here String”。它基本上扩展(不评估!)它之后的参数(只有一个!)并将其作为字符串重定向到它之前/之后的命令的标准输入(标准输入)。 -
!!:q
被称为 “bang command” 用于 bash 中的历史扩展。它用任何以前键入的命令行替换自己。有关更多信息,请通过运行man history
阅读它的本地手册页(在线手册页没有帮助)。-
!!
代表前面的命令行,是!-1
的同义词。显然!-2
表示倒数第二个命令行。不要忘记减号-
,否则它将返回您输入的第二个(3rd/…)命令。 -
:q
修改了 bang 命令并告诉 bash 将替换用单引号 ('
) 括起来,以防止 shell 进一步扩展。
-
命令变体 2(稍长):
echo !!:q | xsel -ib
-
echo
具有将其所有参数打印到终端标准输出的简单工作。 -
!!:q
被称为 “bang command” 用于 bash 中的历史扩展。它用任何以前键入的命令行替换自己。-
!!
代表前面的命令行,是!-1
的同义词。显然!-2
表示倒数第二个命令行。不要忘记减号-
,否则它将返回您输入的第二个(3rd/…)命令。 -
:q
修改了 bang 命令并告诉 bash 将替换用单引号 ('
) 括起来,以防止 shell 进一步扩展。
-
-
|
是一个管道。它将之前命令的终端输出(“stdout”)重定向到之后命令的终端输入(“stdin”)。 -
xsel
是用于访问 X 剪贴板的 命令行 工具。有关更多信息,请在线阅读其手册页或运行man xsel
。-
-i
参数告诉xsel
从标准输入读取(通常这意味着键盘输入,但我们将在这里重定向一些东西) -
-b
参数指定使用剪贴板而不是 X 的 “primary” 或 “secondary” 选择。
-
命令变体 3(别名):
如果您不想记住经常使用的冗长或复杂的命令,那么 bash 别名是一件很酷的事情。您可以将此命令分配给一个简单的别名,您可以运行它而不是长命令来实现相同的目的。
不幸的是,由于 bang 命令是一种特殊的 Bash 功能,并且在解析别名之前会被扩展,因此您不能简单地对上述变体之一进行别名,因为 !!
部分不起作用。不过有一个解决方法。
要设置别名,请在终端中运行以下行。请注意,您可以选择任何有效的 Bash 变量名称而不是 copylastcommand
:
alias copylastcommand='history -p \!\! | xsel -ib'
然而,这仅对您当前的 Bash 会话是持久的,这意味着别名将在您关闭终端窗口后消失。您可以通过将上面的这一行添加到您的 ~/.bashrc
文件的末尾,或者添加到您的 ~/.bash_aliases
文件(如果有的话)中,使其在每个 Bash 会话中持久化。
再次,对该行进行简短的细分:
-
alias name='command'
是在 Bash 中设置别名的语法。从现在开始,只要您执行name
,command
就会运行。 -
history -p \!\!
将之前执行的命令行输出到标准输出(标准输出)。如果没有-p
开关,它不仅会打印,还会再次运行命令。请注意,我们需要使用反斜杠 (\
) 转义刘海 (!
),否则当我们尝试设置别名时 bash 会扩展它们,这是没有意义的,因为它们需要在别名中。同样,您还可以通过将第二个 bang 替换为-n
来指定第 [n] 个最近的命令,例如\!-2
。 -
|
是一个管道。它将之前命令的标准输出(“stdout”)重定向到之后命令的终端标准(“stdin”)。 -
xsel
是用于访问 X 剪贴板的 命令行 工具。有关更多信息,请在线阅读其手册页或运行man xsel
。-
-i
参数告诉xsel
从标准输入读取(通常这意味着键盘输入,但我们将在这里重定向一些东西) -
-b
参数指定使用剪贴板而不是 X 的 “primary” 或 “secondary” 选择。
-
次佳思路
您可以使用 xclip
:
some_command | xclip -selection c
所以在你的情况下:
youtube-dl .... | xclip -selection c
c
代表剪贴板。
您可能需要先安装 xclip
:
sudo apt-get install xclip
编辑:
如果您只想将您输入的命令(而不是输出)复制到剪贴板,您可以使用 Here 字符串:
xclip -selection c <<<"$(echo foobar)"
或管道:
echo foobar | xclip -selection c
第三种思路
我刚刚为 zsh
制作了一个小脚本,它使用 xclip
来执行此操作:
#!/bin/zsh
export HISTFILE=~/.zsh_history
fc -R
fc -l | tail -n 2 | sed -n '1p' | sed 's/[0-9]* //' | xclip -selection c
此脚本将在 shell/终端中输入的最后一个命令复制到系统的剪贴板。它不适用于典型的远程服务器。
我原以为写这个脚本只需要几分钟,但由于我偶然发现了 zsh
处理历史的方式,所以花了很长时间才让它工作。
其中的 tail -n 2
和第一个 sed
正在处理这个脚本本身的命令被记录在历史记录中的事实,因此它获取两行历史记录并删除最后一行。
这个脚本有效,它有点像一个有趣的谜题,但我真的很好奇是否有更简单或更优雅的方式来使用 zsh
。