注:本文为 "Linux Bash | Capture Output / Recall" 相关文章合辑。
英文引文,机翻未校。
中文引文,略作重排。
Automatically Capture Output of the Last Command Into a Variable Using Bash
使用 Bash自动将最后一个命令的输出捕获到变量中
Last updated: March 18, 2024
Written by: baeldung
Reviewed by: Ashley Frieze
1. Overview
When using commands, we may wish to pass the output of one command into another. This is most commonly achieved using pipes , but when scripting, we may prefer to store the output in a variable so we can process it.
在使用命令时,我们可能希望将一个命令的输出传递给另一个命令。这通常是通过 管道 来实现的,但在编写脚本时,我们可能更倾向于将输出存储在一个变量中,以便对其进行处理。
2. Use Cases
2. 用例
Let's start by looking at a couple of commands with different sizes of outputs. The wc command outputs the count of words in a file, which is a scalar value. The ls command outputs a list of values, which we may then wish to use with mv to move the files somewhere.
让我们先来看一些输出大小不同的命令。wc 命令输出文件中的单词数,这是一个标量值。ls 命令输出一个值的列表,我们可能随后会用它与 mv 一起将文件移动到某个位置。
While the solutions presented are compatible with both use cases, the difference between storing a single value or a list is in how we use the resulting variable.
虽然提供的解决方案适用于这两种用例,但存储单个值或列表的区别在于我们如何使用结果变量。
2.1. Change the Directory Based on the Number of Words of a File
2.1. 根据文件的单词数更改目录
The first use case deals with storing the output of the wc -w command:
第一个用例涉及存储 wc -w 命令的输出:
bash
$ wc -w < file_with_5_words
5
In this case, the file file_with_5_words has 5 words.
在这个例子中,文件 file_with_5_words 包含 5 个单词。
Let's imagine we want to change to the directory whose name corresponds to that output:
假设我们想切换到与该输出对应的目录名称:
bash
$ cd 5
2.2. Move Certain Files Based on the Contents of a Folder
2.2. 根据文件夹内容移动特定文件
The second use case is to move a list of files (those whose extension is txt ) to a directory. To do so, we would first need to list the files:
第二个用例是将一个文件列表(扩展名为 txt 的文件)移动到一个目录中。为此,我们首先需要列出这些文件:
bash
$ ls *.txt
ax.txt ay.txt
The syntax of the mv command is:
mv 命令的语法是:
bash
mv file1 file2 ... targetDir
This means that the command accepts multiple files as input at the same time.
这意味着该命令可以同时接受多个文件作为输入。
These solutions don't require the creation of functions or extra files. They're ideal for occasional use.
这些解决方案不需要创建函数或额外的文件。它们适用于偶尔使用。
By default, the shell stores no information about the output of a command. We can refer back to the exit code of the last command. We can also run the history command to see the command lines of each operation. Thus, we need to run the command a certain way to capture its output.
默认情况下,shell 不会存储有关命令输出的信息。我们可以查看上一个命令的退出代码。我们还可以运行 history 命令来查看每次操作的命令行。因此,我们需要以特定的方式运行命令以捕获其输出。
3.1. Explicitly Using Variables
3.1. 显式使用变量
We can assign a variable to contain the output to stdout of a command:
我们可以将一个变量分配为命令的 stdout 输出:
bash
$ var=$(wc -w < file_with_5_words)
This can also be achieved using backward quotes:
这也可以通过使用反引号来实现:
bash
$ var=`wc -w < file_with_5_words`
The old-style backward quote substitution doesn't preserve the meaning of special characters like KaTeX parse error: Got function '\`' with no arguments as subscript at position 21: ...or the actual \̲`̲ itself. These...(...) treats no character in any special way.
旧式的反引号替换 不会保留特殊字符(如 KaTeX parse error: Got function '\`' with no arguments as subscript at position 11: _、\ 或实际的 \̲`̲)的含义。这些字符需要用反斜...(...) 不会对任何字符进行特殊处理。
With both of these approaches, we're storing the output of the wc -w in a variable named var . We can then use the variable by prefixing the dollar sign before it in a command:
通过这两种方法,我们将 wc -w 的输出存储在一个名为 var 的变量中。然后我们可以通过在命令中在变量前加上美元符号来使用该变量:
bash
$ cd $var
The solution for the second use case is similar, except that the variable contains multiple values. Let's check that with the echo command:
第二个用例的解决方案类似,只是变量中包含多个值。我们用 echo 命令来检查:
bash
$ var=`ls *.txt`
$ echo $var
ax.txt ay.txt
After checking the content of the variable with echo and seeing that it has two files, let's now use it with mv :
在用 echo 检查变量内容并确认它包含两个文件后,我们现在用它与 mv 一起使用:
bash
$ mv $var 5
3.2. What If We Use the Variables Incorrectly?
3.2. 如果错误地使用变量会怎样?
Shell variables don't have a type . We should act as though all variables were strings. Thus, we need to be careful to use the contents of a variable only with commands that can accept them.
Shell 变量没有类型。我们应该将所有变量都视为字符串。因此,我们需要小心,只在可以接受它们的命令中使用变量的内容。
For example, let's see what happens if we use the output from ls (which is a list) with the cd command:
例如,让我们看看如果将 ls 的输出(这是一个列表)与 cd 命令一起使用会发生什么:
bash
$ var=$(ls *.txt)
$ echo $var
ax.txt ay.txt
$ cd $var
-bash: cd: too many arguments
Here, the cd command failed because it accepts only one input value and not multiple values separated with spaces.
在这里,cd 命令失败了,因为它只接受一个输入值,而不是用空格分隔的多个值。
3.3. Using History Expansion -- !!
3.3. 使用历史扩展 -- !!
Though the shell does not track the output of a command, we can use history expansion to re-run a previous command to assign its output to a variable:
虽然 shell 不会跟踪命令的输出,但我们可以使用历史扩展来重新运行之前的命令,以将其输出分配给变量:
bash
$ ls *.txt
ax.txt ay.txt
$ var=$(!!)
var=$(ls *.txt)
$ echo $var
ax.txt ay.txt
Similarly, we can use the number from the output of history to re-run an earlier command:
同样,我们也可以使用 history 输出中的编号来重新运行之前的命令:
bash
$ history
1097 git log
1098 ls *.txt
$ var=$(!1098)
We should note that this approach may produce unwanted results . For example, if the output of the command changes on each invocation, then our variable will contain the output of the most recent call.
我们需要注意的是,这种方法可能会产生不希望的结果。例如,如果命令的输出在每次调用时都会改变,那么我们的变量将包含最近一次调用的输出。
4. Longer-Term Solutions
4. 长期解决方案
If we're capturing command output a lot, we may wish to set up some scripting on our system to help us.
如果我们经常需要捕获命令的输出,我们可能希望在我们的系统上设置一些脚本来帮助我们。
4.1. Using a Bash Function
4.1. 使用 Bash 函数
Let's define a function, out2var , to capture command output and put it in var :
我们定义一个函数 out2var ,用于捕获命令输出并将其放入 var 中:
bash
out2var() {
var=$("$@")
printf '%s\n'$var
}
This takes the command line to execute via the input parameter @ and then stores the output in var . As we want to see the output, we have a printf call.
这通过输入参数 @ 接收要执行的命令行,然后将输出存储在 var 中。因为我们想看到输出,所以我们调用了 printf。
Every time the function out2var is invoked, the variable var is assigned:
每次调用函数 out2var 时,变量 var 都会被赋值:
bash
$ out2var wc -w < file_with_5_words
5
$ echo $var
5
$ cd $var
We may put this function into our current terminal or even add it to our .bashrc file.
我们可以将这个函数放入当前终端,甚至可以将其添加到我们的 .bashrc 文件中。
4.2. Using a Temporary File and an Environmental Variable
4.2. 使用临时文件和环境变量
Rather than run a special wrapper on our commands, we can implement a hook to store the output of every command into a file.
与其为我们的命令运行一个特殊的包装器,我们不如实现一个钩子,将每个命令的输出存储到一个文件中。
This solution uses environmental variables:
这种解决方案使用了环境变量:
bash
$ PROMPT_COMMAND='touch /tmp/last_command; var="$(cat /tmp/last_command)"; exec >/dev/tty; exec > >(tee /tmp/last_command)'
First, we create the temporary file and set the variable name, var , that we will invoke later to retrieve the output. Then, it prints the content of the temporary file located in /tmp/last_command . After the first semicolon, we execute the command with exec in the current console terminal (represented by /dev/tty ). Finally, after the last semicolon, the tee command with the pipe sends the standard output to the temporary file and also to the screen.
首先,我们创建临时文件并设置变量名 var ,稍后我们将调用它来检索输出。然后,它打印位于 /tmp/last_command 的临时文件的内容。在第一个分号之后,我们使用 exec 在当前控制台终端(由 /dev/tty 表示)中执行命令。最后,在最后一个分号之后,带有管道的 tee 命令将标准输出发送到临时文件以及屏幕上。
The use is relatively straightforward, as, after any given command, the output is automatically stored:
使用起来相对简单,因为任何给定命令的输出都会自动存储:
bash
$ ls *.txt
ax.txt ay.txt
$ echo $var
ax.txt ay.txt
$ mv $var 5
This should be the preferred approach if we want to automate the process of capturing outputs. However, this approach has two drawbacks:
如果我们要自动化捕获输出的过程,这应该是首选方法。然而,这种方法有两个缺点:
- We should remember that, as the procedure is automatic, we cannot rely on *KaTeX parse error: Undefined control sequence: \* at position 1: \̲*̲ var multiple...var_ every time we execute one command**.
我们应该记住,由于该过程是自动的,我们不能多次依赖 *KaTeX parse error: Undefined control sequence: \* at position 1: \̲*̲ var。与之前需要显式调...var_ 的内容**。 - It captures the output of every command, which may cause problems with interactive commands (for example, vim ).
它会捕获每个命令的输出,这可能会导致 与交互式命令(例如,vim)出现问题。
To stop the automatic storage of the outputs, we can run:
要停止自动存储输出,我们可以运行:
bash
$ unset PROMPT_COMMAND
5. Conclusion
5. 结论
In this article, we discussed different ways of storing the output of a command in a variable.
在本文中,我们讨论了将命令输出存储到变量中的不同方法。
We saw how to use this variable as part of the input for another command.
我们看到了如何将这个变量用作另一个命令的输入。
We also looked at some scripts we can create to help capture command output more frequently.
我们还查看了一些可以创建的脚本,以帮助我们更频繁地捕获命令输出。
Recalling Previous Commands or Their Arguments in Bash
在 Bash 中召回之前的命令或其参数
Last updated: March 18, 2024
Written by: Kai Yuan
Reviewed by: Eric Martin
1. Overview
When we work on the Linux command line, we often need to recall or reference the previously executed command or some parts of that command in the current one.
在 Linux 命令行中工作时,我们经常需要召回或引用之前执行的命令或其部分内容到当前命令中。
For example, most of us know that we can press Ctrl-p (or the Up-Arrow key) to recall the last command so that we can modify it and press Enter to execute it.
例如,大多数人都知道,我们可以按 Ctrl-p (或 上箭头 键)来召回上一条命令,然后修改它并按 Enter 键执行。
In this tutorial, we'll learn some tricks to reuse different parts from the last command in Bash .
在本教程中,我们将 学习一些在 Bash 中重用上一条命令不同部分的技巧。
All keyboard shortcuts we'll see in this tutorial are based on Emacs-binding, which is Bash's default key-binding.
本教程中我们将看到的所有键盘快捷键都基于 Emacs 绑定,这是 Bash 的默认键绑定方式。
2. Referencing the Last Command in the Current Command
2. 在当前命令中引用上一条命令
We've mentioned pressing Ctrl-p or the Up-Arrow key can bring the last command to the current line. However, sometimes, we want the last command to be a part of the current command.
我们提到过,按 Ctrl-p 或 上箭头 键可以将上一条命令带到当前行。然而,有时,我们希望上一条命令成为当前命令的一部分。
An example may explain this requirement quickly. Let's say we want to create a file under the /opt directory. As regular users, we often execute the touch command but forget to add sudo :
一个例子可以快速解释这一需求。假设我们想在 /opt 目录下创建一个文件。作为普通用户,我们经常执行 touch 命令,但忘记添加 sudo:
bash
kent$ touch /opt/myFile.txt
touch: cannot touch '/opt/myFile.txt': Permission denied
Then, we realized from the error message above that sudo was missing. So we want to prepend sudo to the previous command.
然后,我们从上面的错误信息中意识到缺少了 sudo 。因此,我们希望在上一条命令前加上 sudo。
Of course, we can press Ctrl-p to recall the last command, move the cursor to the right position, and type sudo . Well, "sudo " is short, and moving the cursor (pressing Ctrl-a ) to the very beginning isn't hard to do. However, if we'd like to insert the previous command in the middle of the current complex command, this approach makes us build a complex command by starting from the middle part. Moreover, if we want to reference the last command multiple times in the current command, the Ctrl-p way cannot help us anymore.
当然,我们可以按 Ctrl-p 回召上一条命令,将光标移到正确的位置,然后输入 sudo 。嗯,"sudo " 很短,将光标(按 Ctrl-a )移到最前面也不是很难做到。然而,如果我们想在当前复杂命令的中间插入上一条命令,这种方法就让我们从中间部分开始构建一个复杂的命令。此外,如果我们在当前命令中多次引用上一条命令,Ctrl-p 的方式就无能为力了。
Next, let's see another way to reference the last command in the current line.
接下来,让我们看看另一种在当前行引用上一条命令的方法。
2.1. Using !!
to Reference the Last Command
2.1. 使用 !!
引用上一条命令
We know that we can execute the last command in the command history with the history expansion '!!'. For example:
我们知道可以通过历史扩展 '!!' 执行命令历史中的上一条命令。例如:
bash
$ echo "Linux is awesome!"
Linux is awesome!
$ !!
echo "Linux is awesome!"
Linux is awesome!
So, we can use !! in the current command to reference the last command .
因此,我们可以在当前命令中使用 !! 来引用上一条命令。
Now, let's solve the previous "sudo " problem in this way:
现在,让我们用这种方法解决前面的 "sudo" 问题:
bash
kent$ touch /opt/myFile.txt
touch: cannot touch '/opt/myFile.txt': Permission denied
kent$ sudo !!
sudo touch /opt/myFile.txt
[sudo] password for kent:
kent$ ls -l /opt/myFile.txt
-rw-r--r-- 1 root root 0 Aug 6 00:41 /opt/myFile.txt
Next, let's see another example:
接下来,让我们看看另一个例子:
bash
$ uptime
00:50:46 up 7 days, 8:28, 1 user, load average: 3.20, 3.20, 3.27
$ echo "The output of the cmd: <!!> is: $(!!)"
echo "The output of the cmd: <uptime> is: $(uptime)"
The output of the cmd: <uptime> is: 00:51:05 up 7 days, 8:28, 1 user, load average: 2.99, 3.15, 3.25
In the example above, first, we test the command uptime to check its output. Then, we want to reference the command twice in a new command.
在上面的例子中,我们首先测试了 uptime 命令的输出,然后我们希望在新命令中两次引用该命令。
As we can see, in this case, using !! is pretty handy to solve this problem.
正如我们所见,在这种情况下,使用 !! 非常方便地解决了这个问题。
However, we may have a question -- while !! references the last command, is it possible to use it if we'd like to make some changes based on the last command?
然而,我们可能会有一个问题------虽然 !! 引用了上一条命令,但如果我们要根据上一条命令进行一些修改,是否可以使用它呢?
The answer is "yes". So next, let's look at performing history expansion in Bash.
答案是 "可以"。接下来,让我们看看在 Bash 中执行历史扩展。
2.2. Performing History Expansion
2.2. 执行历史扩展
In Bash, we can perform history expansion by pressing M-^ . It's worth mentioning that, here, 'M ' is the Alt key, and '^' is Shift-6 . So, in other words, pressing Alt-Shift-6 performs history expansion on the current line.
在 Bash 中,我们可以通过按 M-^ 来执行历史扩展 。值得一提的是,这里的 "M " 是 Alt 键,而 "^" 是 Shift-6 。换句话说,按下 Alt-Shift-6 将在当前行执行历史扩展。
As usual, let's understand it through a simple example:
像往常一样,我们通过一个简单的例子来理解它:
bash
kent$ touch /opt/tehFile.txt
touch: cannot touch '/opt/tehFile.txt': Permission denied
As the example shows, we try to create a file called "theFile.txt " under /opt . But, again, we forget to type sudo . Further, we've made a typo: "teh ".
如示例所示,我们试图在 /opt 下创建一个名为 "theFile.txt " 的文件。但,我们又忘记了输入 sudo 。此外,我们还打错了字:"teh"。
Next, let's see how to reuse the previous command and fix the typo:
接下来,让我们看看如何重用上一条命令并修正拼写错误:

如演示所示,在输入 "!! " 后,我们按下了 Alt-Shift-6 ,然后 "!!**" 得到了扩展,这样我们就可以对上一条命令进行一些修改了。
3. Referencing the Arguments of the Previous Bash Command
3. 引用上一条 Bash 命令的参数
We've learned how to reference the entire previous command in the current command. In practice, we often want to reference some parts from the last executed command, such as some arguments. For example, we first edit a file using the Vim editor:
我们已经学会了如何在当前命令中引用上一条完整的命令。在实践中,我们经常希望引用上一条执行的命令的某些部分,例如某些参数。例如,我们首先使用 Vim 编辑器编辑一个文件:
bash
$ vim /a/file/sits/deeply/in/some/directory/file.txt
After we save the changes and exit Vim, we want to copy the file to another directory. So, it would be pretty convenient if we could reference the argument of the previous vim command:
保存更改并退出 Vim 后,我们希望将文件复制到另一个目录。因此,如果能够引用上一条 vim 命令的参数,将会非常方便:
bash
$ cp <reference the file of the vim command> /other/dir
To make the problem more general, let's execute an echo command with seven arguments:
为了使问题更具普遍性,我们来执行一个带有七个参数的 echo 命令:
bash
$ echo one two three four five six seven
one two three four five six seven
Next, in the current command, we would like to reference one or several parameters from the echo command.
接下来,在当前命令中,我们希望引用 echo 命令的一个或多个参数。
3.1. Understanding Word Designators in Bash's History Expansion
3.1. 理解 Bash 历史扩展中的单词设计符
Before we address how to reference desired arguments from the previous command, let's first understand how Bash's word designators work.
在我们探讨如何引用上一条命令中所需的参数之前,让我们首先了解 Bash 的单词设计符是如何工作的。
Bash indexes the previous command's words as a zero-based array . For example, our echo command is indexed in this way:
Bash 将上一条命令的单词索引为一个基于零的数组 。例如,我们的 echo 命令是这样索引的:
bash
echo one two three four five six seven
---- --- --- ----- ---- ---- --- -----
0 1 2 3 4 5 6 7
As we can see, index 0 indicates the command itself. Then, from the first argument until the last one, we have index 1 -- n.
正如我们所见,索引 0 表示命令本身。然后,从第一个参数到最后一个参数,我们有索引 1 -- n。
Bash's history expansion supports several ways to reference arguments in the previous command. Let's take our echo command as an example to learn some commonly used expansions:
Bash 的历史扩展支持几种引用上一条命令参数的方法。让我们以我们的 echo 命令为例,学习一些常用的扩展:
-
!:$
-- referencing the last argument -> "seven "
!:$
-- 引用最后一个参数 -> "seven" -
!:n
-- referencing the n-th argument, for example:!:0
-> "echo ",!:5
-> "five "
!:n
-- 引用第 n 个参数,例如:!:0
-> "echo ",!:5
-> "five" -
!:\*
-- referencing all arguments -> "one two three .... seven "
!:\*
-- 引用所有参数 -> "one two three .... seven" -
!:x-y
-- referencing arguments in the given range, for instance,!:3-5
-> "three four five "
!:x-y
-- 引用指定范围内的参数,例如,!:3-5
-> "three four five"
Now that we understand how history expansion works together with the previous commands' argument indexes, referencing them in the current command isn't a challenge for us at all.
现在我们已经理解了历史扩展是如何与上一条命令的参数索引一起工作的,那么在当前命令中引用它们对我们来说就不是什么挑战了。
3.2. Getting Any Parts From the Previous Command
3.2. 获取上一条命令的任何部分
Now, let's see a few examples of using those history expansions in action. For simplicity, let's assume the previous command is always "echo one two ... seven ".
现在,让我们看看一些使用这些历史扩展的实际例子。为了简单起见,我们假设上一条命令总是 "echo one two ... seven"。
First, let's reference the first and the last arguments in a new command:
首先,让我们在新命令中引用第一个和最后一个参数:
bash
$ echo "!:^ and !:$"
echo "one and seven"
one and seven
Next, let's reference from the second until the sixth argument:
接下来,让我们引用从第二个到第六个参数:
bash
$ echo "arg 2nd-6th: !:2-6"
echo "arg 2nd-6th: two three four five six"
arg 2nd-6th: two three four five six
Finally, let's reference the fourth argument twice and then the second argument:
最后,让我们两次引用第四个参数,然后引用第二个参数:
bash
$ echo "The 4th, 4th, 2nd: !:4 !:4 !:2"
echo "The 4th, 4th, 2nd: four four two"
The 4th, 4th, 2nd: four four two
3.4. Using Keyboard Shortcuts
3.4. 使用键盘快捷键
So far, we've seen how to reference different parts from the previous command by history expansion. However, sometimes, we want the history expansions to get expanded so that we can verify if we've referenced the expected arguments or make some changes to the arguments.
到目前为止,我们已经看到了如何通过历史扩展引用上一条命令的不同部分。然而,有时,我们希望历史扩展能够展开,以便我们可以验证是否引用了预期的参数,或者对参数进行一些修改。
We've learned pressing Alt-Shift-6 can perform history expansions in the current command. This shortcut works for argument references too:
我们已经了解到,按下 Alt-Shift-6 可以在当前命令中执行历史扩展。这个快捷键也适用于参数引用:
Further, we can use the following shortcuts to recall arguments from the previous command directly without writing history expansions :
此外,我们可以使用以下快捷键 直接回忆上一条命令的参数,而无需编写历史扩展:
-
Alt-
. -- The last argument
Alt-
. -- 最后一个参数 -
Alt-n
-. -- The n-th argument ( When pressing n and the dot key, the Alt key should always be pressed and held. )
Alt-n-
. -- 第 n 个参数(在按下 n 和 点 键时,应始终按住 Alt 键。)
Next, let's see a demo of recalling the last, the fifth, and the first arguments from the previous command:
接下来,让我们看看一个从上一条命令中回忆最后一个、第五个和第一个参数的演示:
As the demo shows, when we've pressed Alt-5 , Bash prompts (arg: 5) at the beginning of the line. Then if we press the dot key with the Alt key held, "five " is inserted into the cursor position.
如演示所示,当我们按下 Alt-5 时,Bash 在行首提示 (arg: 5) 。然后,如果我们按住 Alt 键并按下 点 键,"five" 就会被插入到光标位置。
4. Conclusion
4. 结论
In this article, we've explored using Bash's history expansion to reference the previous command entirely or only the desired arguments.
在本文中,我们探讨了使用 Bash 的历史扩展来引用上一条完整的命令或仅引用所需的参数。
Moreover, we've learned keyboard shortcuts to perform history expansions or recall any arguments of the last command in the current command.
此外,我们还学习了执行历史扩展或在当前命令中回忆上一条命令的任何参数的键盘快捷键。
With these techniques in mind, we can work with the command line more productively.
掌握了这些技巧,我们可以更高效地使用命令行。
在终端快速选中上一个命令的输出内容
Posted on 2021 年 6 月 12 日 by laixintao
在终端中,一个非常常见的操作是选中上一个命令的输出内容。例如,使用文本处理程序处理服务器的 IP 地址,最终得到结果后需要将其复制给同事或粘贴到工单系统中;或者使用 date
命令转换日期格式,然后将结果复制到其他地方使用;最常见的操作之一是使用 date +%s
命令获取当前时间戳,然后复制该时间戳。如果你经常使用终端,那么每天可能需要重复这种操作数十次。
本文将讨论如何高效地完成这一操作:复制上一个命令的输出结果。虽然看似简单,但为了节省几秒钟的时间,我曾苦苦思索多年,也发现许多人同样在寻找高效的方法。这篇文章将介绍几种实现这一操作的方法,虽然我最终使用的方法并非我首创,但其背后的巧妙思路和技巧同样精彩。希望这篇文章能帮助读者每天节省几秒钟,同时也能带来一些乐趣。
笨拙的方法
最显而易见的方法是使用鼠标。为了复制上一个命令的输出内容,我们需要将手从键盘移开,放到鼠标上,选中文本,然后按下 Command
+ C
(在其他系统中可能是其他按键组合),将内容复制到剪贴板中。
这种方法显而易见地浪费时间。首先,任何需要将手从键盘移开的操作都是低效的;其次,选中操作本身也并非易事,需要两次定位文本的开头和结尾。相比之下,键盘操作是二进制的,按下就是按下,不按就是不按,即使闭上眼睛也能操作。而鼠标操作需要精确的定位,闭上眼睛是无法完成的。如果需要复制的命令输出较长(例如 cat info.log | grep code=404 | tail
的日志输出),则同时使用鼠标进行定位和翻页将变得极为困难。
这种增加心智负担的方法显得非常不人性化。
朴素的方法
Unix 系统中的管道是一个伟大的发明。由于终端中程序的输出是标准输出(stdout),理论上我们可以使用一个程序将标准输出导入到系统剪贴板中。例如,在 Mac OS X 上可以使用 pbcopy
将程序的输出内容导入到剪贴板中,然后使用 pbpaste
或直接按下 Command
+ V
粘贴出来。

在其他 Linux 系统中,也可以实现类似的功能,例如使用 xsel 和 xclip。其原理非常简单,只需调用系统提供的剪贴板相关 API,将标准输入(stdin)的内容写入即可。
类似的工具还有很多,例如 fpp。它可以自动识别标准输出中的文件路径,并提供一个图形界面供用户选择文件,按下 Enter
键即可打开。例如,可以使用 git stat | fpp
。
这种方法的优点是可靠,不涉及鼠标操作。虽然效率也并非特别高,因为需要输入较多的字符(但可以通过别名简化)。
这种方法的最大缺点是不直观。很多时候需要先输入命令查看标准输出,确认无误后再输入相同的命令并附加 | pbcopy
将其复制到剪贴板中。在运行时间较长或资源消耗较大的情况下,这种方法显得不太合适。虽然可以使用 tee
程序同时将输出写入标准输出和管道中,但这样一来命令的复杂度又增加了。这种复杂的命令难以形成肌肉记忆,因此本质上效率也不算特别高。
优雅的方法
另一种简单而直观的方法是使用 iTerm2 自带的功能。在 iTerm2 中,可以通过选择 "Edit -> Select Output of Last Command" 来选中上一条命令的输出,快捷键为 Command
+ Shift
+ A
。

如果该选项为灰色,说明尚未安装 Shell 集成。在菜单栏中选择 "Install Shell Integration" 即可。iTerm2 将执行一个 Curl xxx | bash
命令来安装相关依赖。

这种方法的优点是操作简单,只需一个快捷键即可完成选中和复制,无需再按下 Command
+ C
。如果大部分时间都使用 iTerm2 作为终端模拟器,那么这种方法已经足够。
然而,这种方法的缺点也很明显。这是 iTerm2 提供的功能,如果使用的是其他终端模拟器(例如在 Ubuntu 上),则无法使用。此外,其工作原理是基于在 iTerm2 中运行的命令,因此可以捕获命令的输出信息。这带来了一些严重的问题,例如,如果使用 Tmux,则无论在 Tmux 中打开多少个 session 和 window,iTerm2 都将其视为一个程序,因此无法在 Tmux 中成功捕获标准输出。
即使不使用 Tmux,还有一个无法避免的场景是通过 SSH 连接到远程机器。在这种情况下,iTerm2 只能看到一个 SSH 命令,因此如果尝试复制内容,它会将 SSH 命令下看到的所有内容都复制下来(实际上,前面提到的 pbcopy
也无法在远程机器上工作)。
为了在 SSH 下也能正常工作,必须不区分是在远程机器上执行的命令还是在本地执行的命令,而是从整个终端模拟器的缓冲区入手。使用正则匹配可能是一个好的方法。
黑客的方法
由于没有一个方法能够既省心又省力地完成这个任务,我多年来一直为此感到烦恼。
有一天,在 Hacker News 上看到有人分享了 Tmux 复制文本的操作方法,我点进去阅读后有些失望,因为这些内容我已经知道了。然而,当网页加载完成并播放了播客中的 GIF 时,我发现其中有一段是在命令的输出之间跳来跳去的!这正是我多年来苦苦寻找的东西!

在确认这并非 Tmux 本身的功能后,我给作者发邮件询问他是如何在 Tmux 中快速选择上一个命令的输出的。
没想到作者很快回复了我的邮件。
整个思路非常简单,只需使用一个脚本即可实现,只用到了 Tmux 自身的命令。核心思想是复制当前光标所在的 Shell Prompt 和上一个 Shell Prompt 之间的内容,通过 Tmux 的命令控制光标移动并选择文本。

脚本如下(现在作者有一篇博客,Quickly copy the output of the last shell command you ran,详细介绍了这个脚本的每一步操作)。
shell
bind -n S-M-Up {
copy-mode
send -X clear-selection
send -X start-of-line
send -X start-of-line
send -X cursor-up
send -X start-of-line
send -X start-of-line
if -F "#{m:*➜\u00A0*,#{copy_cursor_line}}" {
send -X search-forward-text "➜\u00A0"
send -X stop-selection
send -X -N 2 cursor-right
send -X begin-selection
send -X end-of-line
send -X end-of-line
if "#{m:*➜\u00A0?*,#{copy_cursor_line}}" {
send -X cursor-left
}
} {
send -X end-of-line
send -X end-of-line
send -X begin-selection
send -X search-backward-text "➜\u00A0"
send -X end-of-line
send -X end-of-line
send -X cursor-right
send -X stop-selection
}
}
bind -n
的意思是将此操作绑定到 root key table,默认情况下绑定到 Prefix table。改为绑定到 root 后,此操作无需按下 Tmux 的 Prefix key。S-M-Up
表示同时按下 Shift
+ Option
+ Up
键,即将这三个键绑定到下面的脚本。
然后,此脚本进入 copy-mode,先将光标移动到行首。之后分为两个 block。首先看 if
不满足的下面那个 block,基本上是向前寻找之前的 Shell Prompt。如果找到,则从这里开始复制,这样两个 Shell Prompt 之间的内容就被选中了。再来看 if
里面的内容,意思是如果当前行有 Shell Prompt,则直接复制整行。这样就可以依次向上选中上一个 output、上一个命令、再上一个 output、再上一个命令...... 缺点是只能向上选择,不支持向下选择。不过,这已经足够用了。if
里面的嵌套 if
是处理 Tmux 在 vi 的 copy-mode 下的一个特殊情况,详细解释可以参考原文。
这里有一个需要注意的地方:如果 Shell Prompt 的格式中包含空格,例如以 $␣
结尾,在 Tmux 的复制模式下,对于没有执行过命令的行(例如多按了几次回车),Tmux 会直接将这些行中 Shell Prompt 的空格删除,这会导致脚本无法匹配到空格。例如,在下面的 Shell 中,复制模式下在 date
和 echo
命令之间的三行就没有空格了。

解决方法是将 Shell Prompt 最后的空格改为 Non-breaking space,其 Unicode 编码为 \u00A0
(可以看到,上面的脚本匹配的就是这个 Unicode)。如果使用 Vim,可以在输入模式下按下 Ctrl
+ V
,进入 ins-special-keys 模式,然后依次输入 u 0 0 a 0
,即可输入这个 Unicode 字符。
这种方法对我来说几乎是一个完美的解决方案。如果阅读作者的博客,就会发现其中的坑实在太多了,例如 Tmux 在 vi 的 copy mode 下的行为、删除空格的行为、跳转行为(在行被 Wrap 的情况下必须执行两次 start-of-line
才能真正跳转到行首等)。估计作者也花了很长时间才写好这个脚本。
在 SSH 的情况下,理论上也可以实现,因为这种方法是针对 Tmux 显示的缓冲区进行操作的。但需要修改脚本的匹配规则,因为远程主机的 Prompt 可能与本地计算机不同。将上面的脚本中的 search-forward-text
改为 search-forward
,就可以按照正则表达式进行搜索。
未实现的方法
这种方法是我很久之前的一个尝试,但至今仍未完成。
之前看到过一个项目:
- GitHub - dequis/tmux-url-select: Keyboard based URL selector that integrates with tmux
https://github.com/dequis/tmux-url-select
它可以快速选择当前 Tmux 窗口中的 URL 并复制或打开。
查看代码,发现其思路非常巧妙。具体步骤如下:
- 捕获当前窗口的全部内容;
- 打开一个新的窗口,覆盖原来的窗口;
- 新窗口实际上是一个新的 GUI 程序,将老窗口的内容显示出来,并在该程序中实现选择、跳转和定义按键等功能。
由于用户实际上是进入了一个新的程序,但该程序通过修改 Tmux 窗口的名字,让用户感觉仍然在 Tmux 中。由于这是一个新的程序,它可以不受限制地完成任何事情。
看到这个项目后,我第一个想法是将其 fork 过来,将选择 URL 改为选择上一个命令的输出。理论上应该是可行的。至今仍未完成的原因是......这个项目是用 Perl 写的,而 Perl 的可读性较差。
Ian(上文提到的作者)也表示,这种思路虽然有趣,但从长期来看,不如花时间改进 Tmux 自身的 copy mode 更有意义。他计划为 Tmux 提交补丁。
其他方法
在与作者 Ian 的交流中,他还向我介绍了其他一些实用的工具。
tmux-thumbs 非常有趣。它类似于 vimium/vimperator 的操作模式,可以通过按键快速选择当前缓冲区中的文本块。
- GitHub - fcsonline/tmux-thumbs: A lightning fast version of tmux-fingers written in Rust, copy/pasting tmux like vimium/vimperator
https://github.com/fcsonline/tmux-thumbs
extrakto 与上述工具类似,但使用的是 fzf 模式。可以通过模糊搜索查找当前缓冲区中出现过的文本并快速选中。不过,它似乎无法将内容复制到剪贴板。
- GitHub - laktak/extrakto: extrakto for tmux - quickly select, copy/insert/complete text without a mouse
https://github.com/laktak/extrakto
2021 年 07 月 06 日更新:
我发现在服务器上复制命令时,连同命令本身以及提示符一起复制更加实用,因为我们的提示符带有机器的主机名、标签、IP 地址等信息。复制命令可以让同事知道这个输出是如何生成的,例如打开的文件路径、使用的 awk
或 grep
等,都能一目了然。因此,我将脚本进行了修改,← 是只复制输出,↑ 是向上复制提示符、命令以及输出,↓ 也是如此,但方向是向下选择。
详情见:https://twitter.com/laixintao/status/1412081667498332161
实现代码如下(commit,可以关注 myrc 仓库,我将所有配置文件都放在这里,从这里可以看到最新版本):
shell
bind -n S-M-Up {
copy-mode
send -X clear-selection
send -X start-of-line
send -X start-of-line
send -X cursor-left
send -X begin-selection
send -X search-backward "(\\$ )|(# )"
send -X start-of-line
send -X start-of-line
send -X stop-selection
}
bind -n S-M-Down {
copy-mode
send -X clear-selection
send -X end-of-line
send -X end-of-line
send -X search-forward "(\\$ )|(# )"
send -X start-of-line
send -X start-of-line
send -X begin-selection
send -X search-forward "(\\$ )|(# )"
send -X search-forward "(\\$ )|(# )"
send -X start-of-line
send -X start-of-line
send -X cursor-left
send -X stop-selection
}
N 种方式复制上一条命令的输出
23 December 2021
在写技术 Blog 的时候,经常会遇到粘贴一段命令及其输出的情况。对于粘贴上一条命令有很简单的方法,读取 history
文件就好了,比如下面这条 alias
bash
alias '@cpc'='echo -n $(fc -l -1 | awk "{\$1=\"\";print substr(\$0,2)}") | xclip -select clipboard'
对于命令的输出,因为默认没有写入文件。想要复制的时候总是处于事后的状态,本文分享几种方式去简化这一操作
The first Way
重复执行上一条命令然后将输出通过管道发送到剪贴板,比如
bash
$ !! | xclip -select clipboard
!!
是指代上一条命令,shell 会自动展开,同样的还有 !-2
, !-3
分别指代向上第 N 条命令。
缺点:
需要重复执行命令,对于没有幂等或者有 side effect 的情况下,同一条命令多次执行输出可能都不一样
The second way
第二种方式使用 PROMPT_COMMAND
,这个是 Bash 独有的。对于 Zsh 的用户,可以通过 precmd
这个 hook 来做这件事情
bash
precmd() { eval "$PROMPT_COMMAND" }
Bash 会在显示 PS1
变量之前执行 PROMPT_COMMAND
,比如
Shell
[kumiko@misaka ~]$ echo $PS1
[\u@\h \W]\$
[kumiko@misaka ~]$ export PROMPT_COMMAND="date +%H:%M:%S"
13:01:50
[kumiko@misaka ~]$ echo 'hello'
hello
13:01:53
我们可以看到时间被显示在每次输出 PS1
中的内容 [kumiko@misaka ~]$
之前(此处不能理解为每次命令执行后输出时间)。利用这个 hook 我们可以 Hack 掉 File Descriptors,代码如下
bash
export PROMPT_COMMAND='LAST="`cat /tmp/cmd_output`"; exec 1>/dev/tty; exec 1> >(tee /tmp/cmd_output)'
这条命令由三部分组成,可能对于 shell 不熟悉的同学比较奇怪 exec >/dev/tty
是什么意思。因为大多数情况下,exec
的使用场景是替换当前进程空间,执行一条命令。这里是 exec
的另一个用法,打开指定的 FD
进行读写。比如
bash
$ echo 'hahah' > a.txt
$ exec 0< a.txt; cat # 0< 要连在一起,否则会判断 0 是一条命令字符串
hahah
对于一个进程的 FD
,默认情况下是
- 0:
STDIN
- 标准输入 - 1:
STDOUT
- 标准输出 - 2:
STDERR
- 标准错误输出
当我们没有参数执行 cat
的时候,STDIN
实际上是打开的 /dev/tty
,所以会从当前终端读取数据,然后进行回显。但是前面的 exec 0< a.txt
将默认的 0 号 FD
的指向替换成了一个读取 a.txt
的 FD
,就相当于我们平常使用的重定向。知道了这点,上面的命令便不难理解了。LAST
变量保存的是一个执行过程,对应着 /tmp/cmd_output
文件的内容。exec 1>/dev/tty
将标准输出定向到 /dev/tty
,所以我们可以在终端看到命令的输出,exec 1> >(tee /tmp/cmd_output)
相当于 dup
了 FD
,使得标准输出还会在 /tmp/cmd_output
中写入一份
然后我们的 $LAST
就是上一条命令的输出了,效果如下

如果需要同时支持 STDOUT
和 STDERR
,可以使用下面命令,原理相同
bash
export PROMPT_COMMAND='LAST="`cat /tmp/cmd_output`"; exec 1>/dev/tty; exec 1> >(tee /tmp/cmd_output); exec 2>/dev/tty; exec 2> >(tee /tmp/cmd_output);'
缺点:
- 如果你有多个 Shell 进程同时执行命令,会出现单文件同时写入的情况。这里需要每个 Shell 分配一个独立文件名称,比较麻烦
The third way
个人目前使用的方式。我们先来观察一下终端中,执行命令后的输出有什么特点。我这里是 starship 和 Zsh 的组合,其他的可以照抄然后自己改动一下

两个 PS1
之间就是我们的命令 + 输出部分。命令正常执行成功后显示的是绿色的 ❯
,如果上一次命令的 ExitCode
不为 0,那么显示的是红色的 ❯
。此符号在 starship 中可以进行配置,参考文档 https://starship.rs/config/#character
success_symbol
: The format string used before the text input if the previous command succeeded.error_symbol
: The format string used before the text input if the previous command failed.
这里顺便提一下 starship 的原理,其本质是 Hack 掉PROMPT
变量,更改为执行 starship
的二进制文件,并将 Shell 中的上下文作为参数传入,比如 STARSHIP_CMD_STATUS
就是上一条命令的 ExitCode
。通过一番组合后输出 PS1
,参考 starship.zsh#L95
根据以上信息我们可以将 success_symbol
和 error_symbol
作为锚点,然后模拟文本选择。下面有两种方式
- 对于支持快捷键选区的 Terminal,比如 Alacritty。可以通过
xdotool
来发送按键指令,通过脚本替代人工选择 - 对于 Tmux 下,我们可以编写 Tmux Script 来做
这里我选择更加通用的 Tmux 来进行说明:
第一步,为了让我们可以移动光标进行区块选择,我们要先进 copy 模式
bash
copy-mode
然后根据清除当前的已有的选区,这步是避免环境不干净,确保在一个当前没有任何选区的情况下执行命令
bash
send -X clear-selection
下面我们开始移动光标,先移动到行首,因为我们当前有可能已经输入了文字
bash
send -X start-of-line
send -X start-of-line
需要注意,这里需要执行两次,因为有逻辑行和物理行的概念。比如我的宽度只有16个字符,如果我输入了 17 个字符那么会产生折行,但是逻辑上我没有换行的。执行两次我们能够到达真正的行首。之后我们需要向上移动光标
bash
send -X cursor-up
send -X cursor-up
send -X cursor-up
因为默认的 starship 配置有一项 add_newline = True
导致每次命令执行后会换行一次,所以我们着力需要执行 3 次才能到达上一条命令输出的最后一行。目前光标还在最后一行输出的行首,我们需要移动到行尾,同样移动两次
bash
send -X end-of-line
send -X end-of-line
开始进行选区
bash
send -X begin-selection
我们向前搜索,找到上一条命令的开始处。这里不是大于符号,是一个 unicode 字符,可以直接复制过来
bash
send -X search-backward-text "❯"
我们向下一行就是输出结果的开始处,这里是移动到行尾然后向右一个光标就自动到下一行的行首了
bash
send -X end-of-line
send -X end-of-line
send -X cursor-right
结束选区,并复制
bash
send -X stop-selection
send -X copy-selection-and-cancel
上面还有点小瑕疵,如果我的命令输出里面包含了 ❯
怎么办,选区就不完整了。我目前采用的方法使用零宽字符来当作锚点。比如 \u200b
。需要配置一下 starship
bash
[character]
success_symbol = "[❯](bold green)\u200b"
error_symbol = "[❯](bold red)\u200b"
vicmd_symbol = "[❯](bold green)\u200b"
然后将查找条件改为
bash
send -X search-backward-te "❯\u200b"
以上完整代码如下,根据自己的 Prompt 做修改后放到 tmux.conf
种就可以了
bash
bind -n <your key binding> {
copy-mode
send -X clear-selection
send -X start-of-line
send -X start-of-line
send -X cursor-up
send -X cursor-up
send -X cursor-up
send -X end-of-line
send -X end-of-line
send -X begin-selection
send -X search-backward-text "❯\u200b"
send -X end-of-line
send -X end-of-line
send -X cursor-right
send -X stop-selection
send -X copy-selection-and-cancel
}
上述脚本也可以通过 shell 的函数执行
Bash
alias '@cpo'='tmux_copy_cmd_output >> /dev/null 2>&1'
tmux_copy_cmd_output() {
tmux copy-mode
tmux send -X clear-selection
tmux send -X start-of-line
tmux send -X start-of-line
tmux send -X cursor-up
tmux send -X cursor-up
tmux send -X cursor-up
tmux send -X cursor-up # 这里多一次,因为现在我们执行的是一条命令了,需要多敲一个 Enter
tmux send -X end-of-line
tmux send -X end-of-line
tmux send -X begin-selection
tmux send -X search-backward-te "❯\u200b"
tmux send -X end-of-line
tmux send -X end-of-line
tmux send -X cursor-right
tmux send -X stop-selection
tmux send -X copy-selection-and-cancel
}
最终效果如下:

缺点:
- 对其他组件具有入侵性,依赖 Tmux 或者 Alacritty 之类的 Terminal
- 有 Buffer 限制,比如复制一个
seq 1 10000
的输出就失败了
Reference
篇外:讨论
Copy the output of the last command in Terminal.app
将最后一个命令的输出复制到 Terminal.app
11
!! | pbcopy would also run the commands again and couldn't be used with interactive commands.
!! | "pbcopy"也会再次运行这些命令,并且不能与交互式命令一起使用。
This relies on the prompt always being $ :
这依赖于提示符始终为 $ :
bash
tell application "Terminal" to tell window 1 to history
do shell script "/bin/echo " & quoted form of result & ¬
" | ruby -e 'puts $<.read.split(/^\\$ .*?$/)[-2][1..-1]'"
set the clipboard to result
Does anyone know any better options?
有谁知道更好的选择?
asked Nov 19, 2011 at 17:39
Lri
And !! not good for command with side effects
并且"!!"不适合有副作用的命令
-- Rich Homolka
CommentedNov 21, 2011 at 0:41
2
Can you add a real example of what you're trying to accomplish with this? Fill in the blanks "I want to copy the output of the last command, because the last command was and I want to paste it into "
您能添加一个真实的例子来说明您试图用它完成什么吗?填空:"我想复制最后一个命令的输出,因为最后一个命令是____,并且我想把它粘贴到___"
-- Doug Harris
CommentedNov 21, 2011 at 18:40
-
@DougHarris I'd just want to assign a keyboard shortcut to a general purpose script for copying the previous output. That fill in the blanks thing is insanely patronizing BTW.
-
@DougHarris 我只是想为用于复制先前输出的通用脚本分配一个键盘快捷键。顺便说一句,那个填空的事情太盛气凌人了。
-- Lri
Commented Nov 21, 2011 at 19:36
You might consider it patronising, but it's often the best way to succinctly understand what a user wants.
您可能会认为这是居高临下的,但这通常是简洁地了解用户需求的最佳方式。
-- Chris Down
CommentedNov 22, 2011 at 16:23
You could make exec script $( date +%Y%m%d-%H%M%S )
your Terminal startup command to log everything to a dated log file. One unfortunate side effect is that script
is a lousy shell (e.g. always 80 wide) in my limited testing.
你可以将"exec script $( date +%Y%m%d-%H%M%S )"设置为终端启动命令,以便将所有内容记录到带有日期的日志文件中。一个不幸的副作用是,在我有限的测试中,"script"是一个糟糕的 shell(例如,宽度始终为 80)。
-- Daniel Beck ♦
CommentedNov 28, 2011 at 20:06
Add a comment
2 Answers
If you are using at least el Capitan you can use Cmd-shift-A to select the output of the last command and Cmd-C to copy it. Unfortunately this doesn't work for previous versions.
如果你至少在使用"el Capitan",你可以使用 Cmd+shift+A 来选择最后一个命令的输出,然后用 Cmd+C 来复制它。不幸的是,这不适用于以前的版本。
Edited to add updates from the comments:
编辑以添加来自评论的更新:
- this also works for other than just the latest command: first select any part of the output of any previous command manually, and then hit Cmd + Shift + A
这不仅适用于最新命令:首先手动选择任何先前命令输出的任何部分,然后按 Cmd + Shift + A
- after trying this shortcut in iTerm, it asks to install some Shell Integrations and then this keyboard shortcut starts working in iTerm as well, see https://superuser.com/a/1242752/676978 for more details
在 iTerm 中尝试此快捷方式后,它会要求安装一些 Shell 集成,然后此键盘快捷方式也开始在 iTerm 中起作用,有关更多详细信息,请参阅 https://superuser.com/a/1242752/676978
edited Dec 31, 2021 at 4:22
answered Dec 19, 2016 at 22:01
Enrico
4
This is great. And this also works for other than just the latest command: first select any part of the output of any previous command manually, and then hit Cmd + Shift + A.
这太棒了。而且这不仅适用于最新命令:首先手动选择任何先前命令输出的任何部分,然后按 Cmd + Shift + A。
-- khuttun
CommentedMar 1, 2021 at 9:08
@JuusoOhtonen when I tried this shortcut in iTerm, it asked me if I wanted to install some Shell Integrations and when I did that, this keyboard shortcut started working in iTerm as well.
@JuusoOhtonen 当我在 iTerm 中尝试此快捷方式时,它问我是否要安装一些 Shell 集成,当我安装后,此键盘快捷方式也开始在 iTerm 中起作用。
-- Ghos3t
CommentedDec 16, 2021 at 18:42
How to quickly get the previous line output in a terminal without using a mouse?
如何在不使用鼠标的情况下在终端中快速获取上一行输出?
15
Linux (e.g. Ubuntu) terminal, is there a method to get the last line? Say I am randomly typing a td
command, which has not been installed on my system, so I will get a message like below. I would like to have a "shortcut" to run sudo apt-get install textdraw
quickly.
Linux(例如 Ubuntu)终端,有没有办法获取最后一行?假设我随意输入一个"td"命令,而我的系统上尚未安装该命令,所以我会收到如下消息。我想要一个能快速运行"sudo apt-get install textdraw"的"快捷方式"。
Is there such a tool or how can I copy the last line to clipboard without using the mouse?
有没有这样的工具,或者我如何在不使用鼠标的情况下将最后一行复制到剪贴板?
bash
username@WorkStation:~$ td
The program 'td' is currently not installed. You can install it by typing:
sudo apt-get install textdraw
username@WorkStation:~$
edited Dec 28, 2015 at 10:15
Chirag Bhatia - chirag64
asked Dec 28, 2015 at 2:33
Daniel
Press the up arrow? Have you tried that? Also check out the history command in Linux, that might work for you as well.
按向上箭头呢?你试过吗?另外,查看一下 Linux 中的"history"命令,那可能也对你有用。
-- Richie086
CommentedDec 28, 2015 at 7:18
Terminal multiplexer programs, tmux and screen, provide the capability of getitng text into a clipboard. However, there might be an easier way in Ubuntu's default GUI, so I suspect an easier answer may be available. Pressing PgUp, Shift-PgUp, or Ctrl-PgUp might allow for scrollback.
终端多路复用器程序"tmux"和"screen"提供了将文本复制到剪贴板的功能。然而,在 Ubuntu 的默认图形用户界面中可能有更简单的方法,所以我怀疑可能有更简单的答案。按 PgUp、Shift+PgUp 或 Ctrl+PgUp 可能会允许回滚。
-- TOOGAM
CommentedDec 28, 2015 at 7:45
3
@Richie086 Please note, what I need is sudo apt-get install textdraw
, not td
. up arrow will only give me the td
@Richie086 请注意,我需要的是"sudo apt-get install textdraw",而不是"td"。向上箭头只会给我"td"
-- Daniel
CommentedDec 28, 2015 at 8:47
Add a comment
5 Answers
7
If you don't mind a little obscenity (I don't), you might want to use the fuck, a tool that does exactly what you asked for.
如果你不介意有点粗俗(我不介意),你可能想使用 the fuck,一个完全能满足你要求的工具。
Well, not exactly, but it solves the same problem. Instead of just getting the latest line, it tries to match the last command you typed.
嗯,不完全是,但它解决了同样的问题。它不只是获取最新一行,而是尝试匹配你输入的最后一个命令。
The Fuck tries to match a rule for the previous command, creates a new command using the matched rule and runs it.
"The Fuck"尝试匹配前一个命令的规则,使用匹配的规则创建一个新命令并运行它。
The examples shown in the repository show several of the scenarios you mentioned.存储库中显示的示例展示了你提到的几种情况。
answered Dec 29, 2015 at 1:33
Alpha
3
In tmux v2.4 and onwards (since this commit https://github.com/tmux/tmux/commit/76d6d3641f271be1756e41494960d96714e7ee58 ) with send-keys -X
. It might be possible in older versions, with a different syntax.
在 tmux v2.4 及更高版本中(自从这个提交 https://github.com/tmux/tmux/commit/76d6d3641f271be1756e41494960d96714e7ee58 )使用"send-keys -X"。在旧版本中可能使用不同的语法。
In .tmux.conf
:
bash
bind ! copy-mode \;\
send-keys -X cursor-up \;\
send-keys -X select-line \;\
send-keys -X cursor-left \;\
send-keys -X copy-selection-and-cancel \;\
paste-buffer
Now, prefix+!
will copy the last line at the current cursor position.
现在,"prefix+!"将复制当前光标位置的最后一行。
cursor-left
can be left out if you want to execute it directly without typing return.
如果你想不输入回车就直接执行,"cursor-left"可以省略。
Note : it won't work if the last line is empty or if it wrapped but it's still useful in most cases
注意:如果最后一行为空或换行,它将不起作用,但在大多数情况下它仍然有用
edited Apr 10, 2018 at 14:25
answered Mar 15, 2017 at 15:07
lbonn
Thanks. But, to prevent execution i have to use paste-buffer -s ''
.
谢谢。但是,为了防止执行,我必须使用"paste-buffer -s ''"。
-- mykhal
CommentedApr 20, 2023 at 9:15
via:
-
Automatically Capture Output of the Last Command Into a Variable Using Bash | Baeldung on Linux
https://www.baeldung.com/linux/capture-output-of-last-command-to-variable -
Recall the Previous Command or Its Arguments in Bash | Baeldung on Linux
https://www.baeldung.com/linux/bash-recall-previous-command -
macos - Copy the output of the last command in Terminal.app
https://superuser.com/questions/359256/copy-the-output-of-the-last-command-in-terminal-app -
ubuntu - How to quickly get the previous line output in a terminal without using a mouse?
https://superuser.com/questions/1018657/how-to-quickly-get-the-previous-line-output-in-a-terminal-without-using-a-mouse -
在终端快速选中上一个命令的输出内容
https://www.kawabangga.com/posts/4256 -
N 种方式复制上一条命令的输出 · Hanaasagi - (ゝω·)~ kira
https://blog.dreamfever.me/posts/2021-12-23-quickly-copy-the-output-of-the-last-shell-command-you-ran/