copying last bash command into clipboard
Asked Answered
M

5

12

Sometimes I need to save the last typed shell command into the clipboard. I can do something like this:

echo !! | xsel --clipboard

Which works successfully.

But when I try to alias the above command:

alias echoxs='echo !! | xsel --clipboard'

Things do not work as expected. In particular, the clipboard contents become literally !!. Obviously, I am missing something about how bash preprocesses commands and aliases. My hope was that an alias, as is intuitive, would be something like a C macro, and that typing the alias would be equivalent to typing its target.

I've tried other approaches and none seem to work. Using HISTFILE inside a script does not work because either commands are cached by the shell session and not immediately written to the file, or multiple terminals mess with the file such that the last command in the file is not always reliably the last command in the current session.

alias='history 1 | xsel --clipboard'

Almost works, except all fails when attempting to modify (eg, cut or sed) the output of history because it is a built-in command.

Is the a way to get the shell's last command through sane stdout?

Michel answered 17/7, 2014 at 14:41 Comment(5)
I still get literal !!Michel
FYI, using "doesn't work" in a question title is generally bad form; better to use a phrase that describes how it doesn't work (hence the edits).Epideictic
bash aliases, unlike csh/tcsh aliases, do not expand parameters. info bash and search for alias for details.Lumbago
@CharlesDuffy I did not want to narrow the scope of my question too much into shell aliases, that is why I tried to title it something a bit more generic. For example, possibly a script could have been the answer (it was not). But you are correct. In any case, I should have titled it, "copying last bash command into clipboard"Michel
I'm curious to know why aliasing doesn't work, but issuing from the terminal does. I encountered the same problem.Ambience
D
14

I'm not sure to understand what you said about "failing when attempting to modify the output of history", so I hope my solution will suit you. I'm using fc to get the last command:

fc -ln -1 | xsel --clipboard

Here are the meaning of the options:

  • l is to use the standard output
  • n is to hide the command history number
  • -1 is to get the last command from the history
Dialyse answered 17/7, 2014 at 15:13 Comment(5)
did not know about fcMichel
fc is the original history-editing command from ksh; the name stands for "fix command". The equivalent of !! in ksh is "fc -e -" ("fix command with no editor", which just runs the command), usually aliased to "r" for "redo".Despondency
If you're on OSX, a spiffy alias I'd recommend for this is alias copyLastCmd="fc -ln -1 | pbcopy". You can quickly call that whenever you need to save a stroke of genius.Acquisitive
To remove the new line at the end of the copied command, you could run this command instead: "fc -ln -1 | tr -d '\n' | pbcopy"Trixie
fc -ln -1 adds more or less POSIX standard-conformant whitespace in front the output (see discussion). My answer https://mcmap.net/q/931379/-copying-last-bash-command-into-clipboard takes care of removing it.Schach
T
1

Client: pass the option -XY to the ssh command to enable (trusted) X11 forwarding for this session:

ssh -XY USER@IP

Server: check /etc/ssh/sshd_config to make sure X11 forwarding is enabled on server

X11Forwarding yes
yum install xclip -y
echo `hostname -I` `hostname` >> /etc/hosts
echo "alias cplastcmd='history 2 | cut -c 8- | head -n 1 | xclip -selection clipboard'" >> ~/.bashrc

Restart bash and type cplastcmd to copy last bash command to clipboard via X11.

Tolley answered 13/6, 2022 at 8:53 Comment(0)
S
1

This is my take, for Wayland environments using wl-clipboard's wl-copy (available in Debian-based distribution via sudo apt install wl-clipboard:

# coco: copy last command to clipboard
# see https://pubs.opengroup.org/onlinepubs/9699919799/utilities/fc.html
# see https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
# see https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html
# see https://www.gnu.org/software/bash/manual/html_node/Bash-History-Builtins.html
# see https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
# see https://lists.gnu.org/archive/html/bug-bash/2024-03/msg00198.html
# 
# if Bash POSIX Mode is on (e.g. via "set -o posix"), cut off 1 character,
# otherwise (if Bash POSIX Mode is off; the default, or e.g. via "set +o posix"), cut off 2 characters

alias coco='( last_command="$(fc -nl 0)" && shopt -qo posix && cutoff=1 || cutoff=2 ; wl-copy "${last_command:$cutoff}" )'

Explanation:

fc -nl 0 (or identically fc -nl -1) unfortunately prefixes additional whitespace in front of the actual command. This whitespace must to be removed. Complicating matters, when Bash POSIX Mode is active, this whitespace is a single tab character, whereas when the default/"normal" non-POSIX mode is active, this whitespace is a tab character, followed by a space character.

The coco alias tests whether Bash POSIX Mode is active, and accordingly cuts off either 1 or 2 characters from $last_command leveraging Bash's Substring Expansion (${parameter:offset}, here ${last_command:$cutoff}).

Schach answered 1/6 at 5:30 Comment(0)
S
0

I have the following alias in .zshrc which I find quite helpful and it achieves the requirement quite smoothly.

# Function to execute before each command with your command as argument
function preexec() {
    PREV_COMMAND=$1
    # echo "Prev command: $PREV_COMMAND"
    echo "\$ $PREV_COMMAND" | pbcopy
}

The following might be useful to get some context

Note: We are not using precmd here but might be useful in this context.

The preexec and precmd functions in Zsh are hooks that are invoked around the execution of a command line. They each serve different purposes:

  1. preexec: This function is executed just before any command line is executed. It's commonly used for things like starting timers, manipulating the command that's about to be run, or recording the command for later use.

  2. precmd: This function is executed before each prompt. It's often used for tasks that should be done before the user is prompted for the next command, such as printing information about the previous command, displaying Git branch information, or updating the title of the terminal.

To understand it better, think of the order of operations when you run a command in the terminal:

  • You type a command and hit enter.
  • The preexec function runs with your command as an argument.
  • Your command is executed.
  • The precmd function runs right before the next prompt is displayed.

The hooks give you an opportunity to run your own code at these specific points in the process. They're powerful tools for customizing your shell, and can be used to implement a wide variety of features.

Shaum answered 8/6, 2023 at 6:53 Comment(0)
G
0

history -p !! | xsel --clipboard

This does not produce the unwanted space.

Gapes answered 13/7 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.