Invoke copy & paste commands from terminal - macos

Is is possible to invoke a copy command (as if the user pressed Cmd+C) from a bash script? Basically I want to write a simple script that I run with a global hotkey and it should take the current selection from the active app, replace something and paste the result. Is this possible?
The best I could come up so far is using pbpaste and pbcopy, but I'd like to automate that if possible.

If you're just trying to modify a text selection, you could use AppleScript.
osascript -e 'try
set old to the clipboard
end try
try
delay 0.3
tell application "System Events" to keystroke "c" using command down
delay 0.2
set text item delimiters to linefeed
set input to (paragraphs of (the clipboard as text)) as text
set the clipboard to do shell script "shopt -u xpg_echo; echo -n " & quoted form of input & " | rev" without altering line endings
tell application "System Events" to keystroke "v" using command down
delay 0.05
end try
try
set the clipboard to old
end try'
The first delay is for releasing modifier keys if the script is run with a shortcut that has other modifier keys than command. The second delay could also be reduced to something like 0.05, but long selections or for example web views often need a longer delay. Without the third delay, the clipboard would sometimes be set to old before the text would get pasted.
the clipboard as text and do shell script convert line endings to carriage returns by default. shopt -u xpg_echo is needed because the echo in sh interprets backslashes inside single quotes by default. If the input is longer than getconf ARG_MAX bytes, you can't use echo and have to either write it to a temporary file or use pbpaste.
pbpaste and pbcopy replace non-ASCII characters with question marks by default in the environment used by do shell script You can prevent that by setting LC_CTYPE to UTF-8.
Telling System Events to click menu bar items would often be even slower, and it wouldn't work in applications that don't have a menu bar or in full screen windows.
Another option would be to create an Automator service. But they also have small delays before they are run. There's a bug where the shortcuts for services don't always work until the services menu has been shown once on the menu bar. And the services aren't available when the frontmost application doesn't have a menu bar or a services menu.

Related

Applescript Occasionally Freezes Automator

I'm trying to use this applescript to modify a file path written to a text file, copy the modified path to the clipboard, set it as variable thePath, use it to pull a Google Drive link from a list, and then copy that link to the clipboard.
Running it within Automator, it sometimes works perfectly but other times it stalls while running this applescript and crashes textedit, and then eventually times out without any specific error messages. Are there any issues with my code that would be causing Automator to freeze?
Note that I've substituted the actual links with link1, link2, etc. for privacy reasons.
on run {input, parameters}
tell application "TextEdit" to activate
tell application "System Events"
key code 125
key code 123 using shift down
key code 123 using shift down
key code 123 using shift down
key code 123 using shift down
key code 123 using shift down
key code 123 using shift down
key code 123 using shift down
key code 123 using shift down
keystroke "x" using command down
keystroke "a" using command down
key code 51
keystroke "v" using command down
keystroke "s" using command down
keystroke "w" using command down
delay 2
end tell
set thePath to the clipboard
set myList to {"link1","link2","link3","link4","link5","link6","link7","link8","link9","link10","link11","link12","link13","link14","link15","link16","link17","link18","link19","link20","link21","link22","link23","link24","link25","link26","link27","link28","link29","link30","link31","link32","link33","link34","link35","link36","link37","link38","link39","link40","link41","link42","link43","link44","link45","link46","link47","link48","link49","link50","link51","link52","link53","link54","link55","link56","link57","link58","link59","link60","link61","link62","link63","link64","link65","link66","link67","link68","link69","link70","link71","link72","link73","link74","link75","link76","link77","link78","link79","link80","link81","link82","link83","link84","link85","link86","link87","link88","link89","link90","link91","link92","link93","link94","link95","link96","link97","link98","link99","link100","link101","link102","link103","link104","link105","link106","link107","link108","link109","link110","link111","link112","link113","link114","link115","link116","link117","link118","link119","link120","link121","link122","link123","link124","link125","link126","link127","link128","link129","link130","link131","link132","link133","link134","link135","link136","link137","link138","link139","link140","link141","link142","link143","link144","link145","link146","link147","link148","link149","link150","link151","link152","link153","link154","link155","link156","link157","link158","link159","link160","link161","link162","link163","link164","link165","link166","link167","link168","link169","link170","link171","link172","link173","link174","link175","link176","link177","link178","link179","link180","link181","link182","link183","link184","link185","link186","link187","link188","link189","link190","link191","link192","link193","link194","link195","link196","link197","link198","link199","link200","link201","link202","link203","link204","link205","link206","link207","link208","link209","link210","link211","link212","link213","link214","link215","link216","link217","link218","link219","link220","link221","link222","link223","link224","link225","link226","link227","link228","link229","link230","link231","link232","link233","link234","link235","link236","link237","link238","link239","link240","link241","link242","link243","link244","link245","link246","link247","link248","link249","link250","link251","link252","link253","link254","link255","link256","link257","link258","link259","link260","link261","link262","link263","link264","link265","link266","link267","link268","link269","link270","link271","link272","link273","link274","link275","link276","link277","link278","link279","link280","link281","link282","link283","link284","link285","link286","link287","link288","link289","link290","link291","link292","link293","link294","link295","link296","link297","link298"}
set the clipboard to item thePath of myList
return input
end run
You could do this with AppleScript, but it would be much more sensible to do this with a shell script, by way of the Run Shell Script action in Automator, selecting the option to pass the input "as arguments". The default shell in macOS is zsh, so stick with that.
The script is short and sweet:
( PATH=/usr/bin:$PATH
basename "$1" | bc
) 2>/dev/null
basename extracts last path component, which, in this case, is the name of the folder, even if the path ends with a trailing slash. The result of this command is then piped through to bc, which performs basic calculations: this is purely to parse the folder name as a number, so that "00007" simply returns "7".
How to make use of this value is entirely dependent on how and where you store the various links from which it selects. Here's one suggestion, which is reasonably simple:
This allows you to hard-code your 300 or so links into a single Automator variable, which a second shell script reads and returns the specific link associated (by line number) with the value obtained from the previous shell script. The link then placed onto the clipboard.

Replace text in an applescript using an applescript

I have several hundred lengthy applescripts to edit where I need to find and replace the following code snippet in various places in each script.
tell application "Adobe Photoshop CC 2015.5"
set myLayer to current layer of current document
if last character of mySport is "s" then
set contents of text object of myLayer to mySport & ""
else
set contents of text object of myLayer to mySport & "'s"
end if
end tell
I want to replace it with
tell application "Adobe Photoshop CC 2015.5"
set myLayer to current layer of current document
set contents of text object of myLayer to mySport & "'s"
end tell
Is there a way to write an applescript to find and replace several lines?
code screen grab
The second problem is how do I deal with the apostrophe contained inside the quotes?
You can probably tell that I'm an artist and not a developer or scripter! I tried to get an answer a while back but unsuccessfully and the problem is now become critical.
Many thanks in anticipation of an answer.
The best would have been to set this subroutine as a separate script library and call it it in each of your scripts. Doing so, only one change would be enough. I advice you to do this way for next time.
I dig to find a way to make change in a script, but that's not that easy. Script Editor as very limited capability for scripting. the work around is to use the GUI scripting, which means that any changes made by Apple in future versions may no longer work.
The script bellow simulate your keyboard action to search & replace CurString to NewString :
set myScript to "Users:imac27:Desktop:Testscript.scpt" -- path to your script
set CurString to "Set B to 2"
set NewString to "Set X to 5"
tell application "Script Editor"
open myScript
activate myScript
delay 2
tell application "System Events"
keystroke "f" using {option down, command down} --mode search & replace
keystroke tab using {shift down} -- got to search area
keystroke CurString -- set the search target
keystroke tab -- goto replace area
keystroke NewString -- set replace value
-- click on menu "Replace all " which is the 7th item of "Search" menu item (=item 14th of menu "Edit")
tell process "Script Editor" to click menu item 7 of menu of menu item 14 of menu 4 of menu bar 1
end tell
compile front document
save front document
close front document
end tell
This script opens the script, it does the search, replaces, clicks on "replace" menu, then it compiles new version, saves it and closes it. If you have many scripts, you must run it through a loop for each script.
I tested it OK with simple line : replace "Set B to 2" by new line "Set X to 5".
However, your issue is more complex because you want to replace several lines, not only 1. I did not found a way to set the search area with multiple lines. I tried with CR (13) or LF (10), but it does not work. May be someone has an idea for that part ?
Also, if you want to add a " in your search or replace patterns, you can use the following :
set Guil to ASCII character 34
Set CurString to "this is a " & Guil & "s" & Guil & " between quotes"
In this case, the CurString value will be : this is a "s" between quotes
I purchased Script Debugger from Late Night Software and it enables the script to access pieces of code and replace them. Mark Alldritt was amazing in the support he offered and the software is now my "first use" destination.
You are sure of your original script and the final script? In this case no hesitation to use xxd and sed below in hexadecimal script which you wrote you can test this script, no danger for your script. Naturally, you change your path and names at your convenience.
set thePath to POSIX path of (choose file)
tell application "Script Editor"
set doc to open thePath
save doc as "text" in POSIX file "/Users/yourname/Desktop/yourscriptold.txt"
close thePath
end tell
set scp to do shell script "xxd -p -c 100000 /Users/yourname/Desktop/yourscriptold.txt " & " | sed -e 's#74656c6c206170706c69636174696f6e202241646f62652050686f746f73686f7020434320323031352e35220a736574206d794c6179657220746f2063757272656e74206c61796572206f662063757272656e7420646f63756d656e740a6966206c61737420636861726163746572206f66206d7953706f727420697320227322207468656e0a73657420636f6e74656e7473206f662074657874206f626a656374206f66206d794c6179657220746f206d7953706f727420262022220a656c73650a73657420636f6e74656e7473206f662074657874206f626a656374206f66206d794c6179657220746f206d7953706f7274202620222773220a656e642069660a656e642074656c6c#74656c6c206170706c69636174696f6e202241646f62652050686f746f73686f7020434320323031352e35220a736574206d794c6179657220746f2063757272656e74206c61796572206f662063757272656e7420646f63756d656e740a73657420636f6e74656e7473206f662074657874206f626a656374206f66206d794c6179657220746f206d7953706f7274202620222773220a656e642074656c6c#' > /Users/yourname/Desktop/yourscriptnew.txt"
set scp to do shell script "xxd -r -p /Users/yourname/Desktop/yourscriptnew.txt >/Users/yourname/Desktop/yournewscript.txt"
do shell script "osacompile -o " & "/Users/yourname/Desktop/temporyname.scpt" & " /Users/yourname/Desktop/yournewscript.txt"
do shell script "rm -f /Users/yourname/Desktop/yourscriptold.txt "
do shell script "rm -f /Users/yourname/Desktop/yourscriptnew.txt "
do shell script "rm -f /Users/yourname/Desktop/yournewscript.txt "

Switching between two Mac terminal windows

I have an interactive bash script running in a Mac OSX bash Terminal window. I would like, from within that script, to
open a second Terminal window, print in it the content of a variable from the script in the first window,
keep that second window open somewhere on the screen while I continue interacting with the first window, and finally
have the second window closed when I do not need it anymore.
Since I am on Mac OSX, I am thinking of using osascript to run Applescript commands opening the second window, pasting the variable content in it and returning control to the first window, but I cannot make it work.
#!/bin/bash
var2print="I want this to print in the text window"
osascript -e '
tell application "Terminal"
tell window 1 # this just renames the first window
set custom title to "Main window"
end tell
do script # this opens a new window
tell window 1
set custom title to "Text window"
set selected to true # my first idea to put focus on this window
activate # my second idea to put focus on this window
end tell
end tell
'
printf "%s\n" "$var2print" # prints in main window, despite all efforts
read -sn 1 -p "Press any key to continue..."
Surprisingly to me, the very last command 'read' also takes place in the main window, but the focus is on the text window and I have to manually select the main window to press a key and end the script.
I have considered letting go of AppleScript and using the gnu-screen command instead, but it seems like overkill for my purpose to simply have some info displayed for a while.
Any help to better understand what's going on and to find a practical solution to switch between terminal windows would be greatly appreciated. W.
You can toggle two windows in Terminal.app with AppleScript this way
tell application "Terminal"
set index of window 2 to 1
end tell
window 1 is always the frontmost window
How about using a dialog box to display your message and go away automagically after a few seconds like this:
#!/bin/bash
bashvar="ZippedyDooDah"
osascript >/dev/null 2>&1 <<EOF
tell application "System Events" to display alert "$bashvar" buttons {"OK"} as warning default button "OK" giving up after 5
EOF
You can do it like this:
osascript -e 'tell app "Terminal" to do script "echo hello"'
Or, you can set a bash variable like this and send that for display:
MSG="FreddyFrog"
osascript<<EOF
tell app "Terminal"
do script "echo $MSG"
end tell
EOF
If you want to send it more than one message, you could make it tell you its tty as the command you pass, then you will have that in a file and you can send it further messages...
osascript -e 'tell app "Terminal" to do script "tty > tty.txt"'
If you now look in the file tty.txt you will see the device special file of the terminal window you created, some thing like /dev/ttys002, then you can do this from your original window
echo "Some stuff" > /dev/ttys002
echo "More stuff" > /dev/ttys002
or, more succinctly
echo hello > $(cat tty.txt)

Copy pure text from clipboard using AppleScript

Situation
Open a Word Document.
Copy some formatted text from inside the document to the clipboard.
Paste it into an instance of CKEditor
CKEditor received smelling M$-style HTML with tons of useless html elements and styles. Even removing formatting using CKEditor's feature does not render pure text.
Desired solution
Could anybody provide an AppleScript, which removes the styled-/HTML-string and pastes the pure text part back to clipboard.
A plus would be a short hint, how to bind the AppleScript to function key.
You don't show how you're copying and pasting currently. It should be possible to use something like this, though:
tell application "Word"
set theData to (the clipboard as text)
set the clipboard to theData
end tell
That will obtain the plain text version of the clipboard data and then replace the clipboard contents (which contains HTML) with the plain text.
To bind the script to a function key, I recommend using Automator to make a service that runs your script and then use the Keyboard pane of System Preferences to assign a key. In fact, I suspect this whole task would be better as a service that receives the text as input rather than attempting to explicitly fetch it from the clipboard.
Old question, but I found that the existing answers do not completely convert the text to plain. They seem to set the font to Helvetica and the size to 12.
However, you can pipe pbpaste and pbcopy to really remove formatting.
In the Terminal:
$ pbpaste | pbcopy
As an AppleScript:
do shell script "pbpaste | pbcopy"
That's it.
set the clipboard to is defined in Standard Additions. You don't need to enclose it in a tell application "Word" ...
set the clipboard to (the clipboard as text)
echo -n doesn't work because AppleScript's do shell script command uses sh, not bash, and sh's echo is a builtin that doesn't accept options. Specify /bin/echo explicitly and it will work:
do shell script "/bin/echo -n " & quoted form of my_string & " | pbcopy"
That will put a plain text copy of my_string on the clipboard.
This worked for me:
do shell script "echo " & total_paying & " | tr -d \"\n\" | pbcopy"
NOTE: When you click compile, the \n will be converted to a literal newline. This is fine. It still works. I tried using echo -n but it was printing the -n in the output.

Applescript conversion to Bash

I would like to make sure that an applescript can be converted to bash. Are there any ideas on how to do this? And if so, I'll place a simple applescript below to give you an example of how the script runs. In more clarity, I simply want a bash script or shell script to do what my applescript is doing. I want it to "enable" or change the default of the switch in system preferences, under "energy saver" that reads ...'start up automatically after a power failure'...:
set uiScript to "click checkbox \"Start up automatically after a power failure\" of list 2 of group 1 of window \"Energy Saver\" of application process \"System Preferences\""
run script "tell application \"System Events\"
" & uiScript & "
end tell"
any ideas on how to convert this script?
Thanks,
-Unimachead
You may not actually need to convert it - you can run AppleScript from within a bash script, using osascript.
$ man osascript
Note that you can run AppleScript either from a file or just include the source on the command line.

Resources