Reputation: 7302
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?
Upvotes: 13
Views: 5459
Reputation: 74
history -p !! | xsel --clipboard
This does not produce the unwanted space.
Upvotes: 0
Reputation: 27832
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}
).
Upvotes: 1
Reputation: 3195
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
}
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:
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.
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:
preexec
function runs with your command as an argument.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.
Upvotes: 0
Reputation: 54
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.
Upvotes: 1
Reputation: 20315
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 outputn
is to hide the command history number-1
is to get the last command from the historyUpvotes: 15