skamsie
skamsie

Reputation: 2726

How to programatically paste to terminal without executing?

Is it possible to type / paste something to the console without executing the command? Something that would emulate the normal Ctrl / Cmd + c, Ctrl / Cmd + v where the text is put on the current line without being executed so the user can continue typing, deleting, etc.

For example I have the following simple script:

#!/bin/bash

echo -n "foo" | pbcopy

pbpaste

Now when I run this, it just echoes foo% and goes on the next line.

Also, even if this would work, I would prefer a solution that works on both mac os and ubuntu (as far as I know pbcopy does not come pre-installed on all linux distros).

EDIT

Edit to explain the scenario better. Imagine the script above is called foo.sh. You run the script ./foo.sh and when it finishes you have a new prompt with only the text "foo"|. The | represents the cursor.

Upvotes: 2

Views: 3228

Answers (2)

ghoti
ghoti

Reputation: 46896

So... You already know about pbcopy and pbpaste in macOS. You probably want to know about xclip, which is a similar interface to X selections ("the clipboard") from the command line.

Each system (Aqua and X) handles clipboard data structures differently, and I'm not aware of any single tool which will function this way on both platforms. That said, you can perhaps write scripts that are portable between both systems:

#!/usr/bin/env bash

if type xclip >/dev/null; then
        clip_copy="xclip"
        clip_paste="xclip -o"
elif type pbcopy >/dev/null ; then
        clip_copy="pbcopy"
        clip_paste="pbpaste"
else
        echo "ERROR: no clipboard functions. Where am I?" >&2
        exit 1
fi

Also note that pbcopy/pbpaste support different data types, whereas xclip just deals with text.

That said, both of these functions deal with stdin and stdout. If you want to actually simulate keypresses (as your edit appears to imply), you need another tool.

In the Mac world, a number of options exist. Cliclick works well for me. This tool has full mouse support, but also has an option t:, which will simulate keyboard input. It seems reasonable that one might cliclick t:"$(pbpaste)", though I've never tried it.

You can also use AppleScript to print arbitrary text:

$ osascript -e 'tell application "System Events" to keystroke "Hello world."'

In X, xdotool seems to work.

$ xdotool type "Hello world."

To make a script which might run in both macOS and X environments, you could key on the output of uname -s:

#!/usr/bin/env bash

case "$(uname -s)" in
  Darwin)
    clip_copy="pbcopy"           # note: $clip_copy isn't used in this script.
    clip_paste="pbpaste"
    type_cmd="osascript -e 'tell application \"System Events\" to keystroke \"%s\"'"
    ;;
  *)
    clip_copy="xclip"
    clip_paste="xclip -o"
    type_cmd='xdotool type "%s"'
    ;;
esac

text="$($clip_paste)"

printf "$type_cmd" "${text//[!A-Za-z0-9. ]/}" | sh

Note: untested. YMMV. May contain nuts.

Upvotes: 3

skamsie
skamsie

Reputation: 2726

Based on a gist in the comments I found a thread on stack exchange that helped me answer my own question: https://unix.stackexchange.com/a/213821.

I am only interested in supporting sh, bash, zsh so the following solution works fine:

#!/bin/bash

if [ "$(echo $ZSH_VERSION)" ]; then
    print -z $@
else
    # assume bash or sh
    bind '"\e[0n": "'"$*"'"'; printf '\e[5n'
fi

Call with source inject.sh echo foo

Upvotes: 0

Related Questions