9

Oftentimes I want to post something to a github bug like

$ ping google.com
PING google.com (216.58.195.238): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 216.58.195.238: icmp_seq=0 ttl=53 time=1064.747 ms

Right now I run the command, use screen's C-a C-[ to highlight the area, enter to copy it to that buffer, paste it into vim, write it to a file and then cat that into pbcopy. There has to be a better way.

Is there a command I can run which will tee the command I type prefixed with a $ and all the output to pbcopy? Or anything close? I envision

$ demo ping google.com
PING google.com (216.58.195.238): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 216.58.195.238: icmp_seq=0 ttl=53 time=1064.747 ms
^C
$

and now the original thing I pasted is in my mac clipboard.

6
  • Is this really specific to OS X?
    – phk
    Oct 20 '16 at 17:40
  • Nope. Whatever utility you use to move from a file to a clipboard on other platforms could be substituted for pbcopy and it would be the same question. Oct 20 '16 at 17:49
  • 2
    Curious: why don't you use the mouse?
    – user601
    Oct 20 '16 at 18:19
  • 2
    You can leave out the whole vim part. Simply run pbcopy and C-a C-] to its stdin.
    – user601
    Oct 20 '16 at 18:23
  • @hop using the mouse is slow and doesn't work well when there are multiple screens worth of text Oct 20 '16 at 21:19
10

One option is to enable tracing (with -x) in a subshell that runs the command. This writes the command to STDERR and the standard output to STDOUT. Collect both and pipe to pbcopy:

$ ( set -x; ping -c 3 google.com ) 2>&1 | pbcopy

$ pbpaste
+ ping -c 3 google.com
PING google.com (173.194.217.138): 56 data bytes
64 bytes from 173.194.217.138: icmp_seq=0 ttl=44 time=37.436 ms
64 bytes from 173.194.217.138: icmp_seq=1 ttl=44 time=38.891 ms
64 bytes from 173.194.217.138: icmp_seq=2 ttl=44 time=39.329 ms
--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 37.436/38.552/39.329/0.809 ms
3
  • set -x is an interesting approach. Well spotted!
    – DopeGhoti
    Oct 20 '16 at 18:49
  • I'd love to also see my command printed out too (preferably on 2 different streams still), and would like + to be $ Oct 20 '16 at 22:43
  • 1
    @PaulTarjan : then change PS4 accordingly. An exemple (not what you need, but shows some possible options) : PS4='\\$ ${BASH_SOURCE[0]:-inherited}:line ${LINENO}:${FUNCNAME[0]:+${FUNCNAME[0]}(): } ' . The "\\$" makes "$" the first char, and that char is then repeated to show the level of call. ($ for first level, $$ for second level, etc) Oct 21 '16 at 11:09
7

You can use the script utility to capture the entire interaction including your prompt, command, and its output:

script temp.log; cat temp.log | pbcopy
[ do stuff ]
[ end the interaction with ^D or logging out of the shell ]

You can then review the file, and its contents will already be on your clipboard.

You can also:

script temp.log 'somecommand'; cat temp.log | pbcopy
3
  • This is close. It included my whole prompt where I just want a $ and it lets me do many commands where I only want one, and it adds a header and footer I don't want. Oct 20 '16 at 18:10
  • 1
    I don't think it can suppress ANSI sequences (as by design it's there to capture the entire session), but you can suppress the header. Check the man page for -q. You can use sed to strip the ANSI codes: sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"
    – DopeGhoti
    Oct 20 '16 at 18:33
  • 2
    You can use script temp.log env PS1='$ ' bash --norc to get a bash with the prompt you want. Alternatively you can edit your ~/.bashrc to check for the use of script and alter the prompt: [ $(ps -o command= -p $PPID) = 'script' ] && PS1='$ '
    – Eric
    Oct 21 '16 at 3:56
1

iterm2 has shell integration that allows you to select (and auto-copy) the output of the last command with cmd-shift-A.

1

From your comment on another answer, you don't want your entire prompt to be copied, but only $.

How I solve this is simply:

16:54:53 [myname mydirectory] 535 $ bash
bash-3.2$ PS1='\$ '
$ echo some command
some command
$ exit
exit
16:57:17 [myname mydirectory] 536 $

Easy. Then I use the mouse to copy and paste the prompt, command, and output that I want.


For a different use case where I just want the command, not its output and not the prompt, to be able to give someone instructions, I've set up an alias, zv (close to "Command V" on the keyboard) to copy the last command to my clipboard:

alias zv='printf %s "$(history -p \!\!)" | pbcopy'

Note the use of printf and command substitution to avoid including the trailing newline from history into the clipboard.

0

Right now I run the command, use screen's C-a C-[ to highlight the area, enter to copy it to that buffer,

If you already use GNU screen you can copy a selection directly using an external tool. For example, I added this to ~/.screenrc on Linux:

bind b eval writebuf 'exec /bin/sh -c " xsel -i </tmp/screen-exchange"' 'exec /bin/sh -c "killall xsel"'

Now I can mark a selection wih Control-a [, press Space and now press Control-a b to run xsel. It's not my idea, it's actually quite common. Note that some people use it with pbcopy instead of xsel so it may work for you without any problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.