need to return "\" not "\\" in applescript to build bash command - bash

Thanks for the help.
I'm trying to build a series of bash commands using Applescript. My problem is applescript using \ as an escape character. so when it returns my strings its returning \\ not \ as needed. Has anyone found a way to return a string with a single \?
Also, previous help I've received on this people will say "if you display dialog it will say \ not \\" which is correct however I'm not attempting to display text I need to pass these strings on to bash.
--get all the finder info
tell application "Finder"
set selCnt to selection as list
if (count of items in selCnt) is equal to 1 then
set theDir to the selection as alias
set theDir to POSIX path of theDir
else if ((count of items in selCnt) is greater than 1) then
display dialog "Please select only one directory. ie: 'Documents'"
else if (count of items in selCnt) is equal to 0 then
set theDir to target of window 1 as alias
set theDir to POSIX path of theDir
else
display dialog "What do you think you're doing?"
end if
end tell
--rename strings with spaces
set t to theDir
set t to tid(t, " ") -- converts to a list of text items
set t to tid(t, "\\ ") -- converts back to tex a list odf text items
on tid(input, delim)
set {oldTID, my text item delimiters} to {my text item delimiters, delim}
if class of input is list then
set outputA to input as text
else
set outputA to text items of input
end if
set my text item delimiters to oldTID
return outputA
end tid
set theDir to result
--strings setup
set cdStr to "cd " & theDir
set stringA to ".doc"
set stringB to "\\"
set delDoc to "find . -name " & quoted form of stringA & " -exec rm {} " & stringB & ":"
set stringA to ".exl"
set stringB to "\\"
set delExl to "find . -name " & quoted form of stringA & " -exec rm {} " & stringB & ":"
--execute shell scripts
set theCmd to cdStr & return & delDoc & return & delExl
return theCmd
(*
do shell script cdStr
do shell script delExl
do shell script delDoc
*)

You simply need to escape a backslash with a backslash to pass on that string.
set foo to "\\"
will set foo to a single "\". You can verify this using any of the following:
display dialog foo
log foo
return foo
do shell script "echo \\$foo"
Run this last command, and it returns "$foo", proving that the shell command correctly received a single slash, which in this instance tells the shell command to ignore the special significance of $. If it had sent two slashes to the shell command, you would've gotten an error, or possibly a literal slash.
You can psych yourself out by getting confused by your editor's display of "\", but the results end up working.
You don't state in your question what is making you think it's not behaving correctly. What does "it freaks out" mean?

I was able to figure everything out using bash commands mostly. Then I was able to create a service which ran when i hit a certain key set like "cmd + option + R." All the user has to do is select the folder and hit the keys and the program will erase all of the files with the specific extension. step 2 from my notes below allow bash to recognize the source which is determined by the first open window of Finder.
Again sorry for all the formatting trouble this is only my second ever post in stackoverflow
first modify the .bash_profile. Open it via terminal
open ~/.bash_profile -a TextEdit
copy and past script into the txt file then save. This allows you to now issue a command “cdf”
cdf () {
theFinderPath=osascript <<END
tell application "Finder"
try
set thePath to get the POSIX path of (folder of the front window as string)
on error
set thePath to get the POSIX path of (path to desktop folder as string)
end try
end tell
END
cd "$theFinderPath";
}
rewrite script to include new command and then save this to the root of your “Documents” folder.
3.
! /bin/bash
cd to the path of the front Finder window
cdf
find . -name ‘.doc’ -exec rm {} \; #deletes all doc files
find . -name ‘.exe’ -exec rm {} \; #deletes all exe files
Now using Automator you can write a simple code that will issue this command from a keystroke.
bash -x /Users/username/Documents/sh/script.sh || true

Related

How to batch rename files in a terminal?

I want to rename the files in a directory to sequential numbers.
stars_01_012.png
stars_01_014.png
stars_01_015.png
stars_01_017.png
stars_02_012.png
stars_02_014.png
stars_02_015.png
stars_02_017.png
And change it into
stars_01_001.png
stars_01_002.png
stars_01_003.png
stars_01_004.png
stars_02_001.png
stars_02_002.png
stars_02_003.png
stars_02_004.png
Relatives but not completely:
How to Batch Rename Files in a macOS Terminal?
How can I batch rename files using the Terminal?
You can do it with rename which you can install on macOS with homebrew using:
brew install rename
The command then looks like this:
rename --dry-run -X -e 'my #parts=split /_/; my $this=$parts[0].$parts[1]; if(!defined($ENV{previous}) || $this ne $ENV{previous}){$ENV{previous}=$this; $ENV{N}=0}; $ENV{N}=$ENV{N}+1; $_ = $parts[0]."_".$parts[1]."_".$ENV{N}' *png
Sample Output
'stars_01_012.png' would be renamed to 'stars_01_1.png'
'stars_01_014.png' would be renamed to 'stars_01_2.png'
'stars_01_015.png' would be renamed to 'stars_01_3.png'
'stars_01_017.png' would be renamed to 'stars_01_4.png'
'stars_02_012.png' would be renamed to 'stars_02_1.png'
'stars_02_014.png' would be renamed to 'stars_02_2.png'
'stars_02_015.png' would be renamed to 'stars_02_3.png'
'stars_02_017.png' would be renamed to 'stars_02_4.png'
'stars_88_099.png' would be renamed to 'stars_88_1.png'
Explanation:
my #parts=split /_/ splits the filename into 3 parts using the underscore as the separator,
my $this=$parts[0].$parts[1] saves the first two parts simply concatenated together, e.g. "stars01",
the if statement tests if either of the first two parts have changed, then
$ENV{previous}=$this; $ENV{N}=0 saves the current stem of the filename in an environment variable called previous and the current sequential counter in another environment variable N,
$ENV{N}=$ENV{N}+1 increments the sequential counter, and
$_ = $parts[0]."_".$parts[1]."_".$ENV{N} creates the new output filename from the various parts.
If that all looks correct, remove the --dry-run and run it again - probably in a spare directory with a copy of your files until you are sure all is ok :-)
The above may be easier to read like this:
#!/bin/bash
rename --dry-run -X -e '
my #parts=split /_/; # split filename into parts based on underscore
my $this=$parts[0].$parts[1]; # save first two parts of filename in $this
# see if it is a new stem
if(!defined($ENV{previous}) || $this ne $ENV{previous}){
$ENV{previous}=$this; $ENV{N}=0}; # save new initial part, reset N
$ENV{N}=$ENV{N}+1; # increment N
$_ = $parts[0]."_".$parts[1]."_".$ENV{N} # formulate new filename from parts
' *png
Change the last line to the following if you want to zero-pad the numbers out to three digits:
$_ = sprintf("%s_%s_%03d",$parts[0],$parts[1],$ENV{N}) # formulate new filename from parts
Note:
I save the previous file prefix and sequential counter into environment variables to preserve them between files - there may be easier ways - if anyone knows, please ping me! Thanks.
You can also create an applescript script, using the Terminal commandline.
below a script to copy in the script editor
set thefile to do shell script "ls The_path_of_your_files" that you wish to rename '"with in common the extension (in your example .png) which gives:
**set thefile to do shell script "ls The_path_of_your_files/*.png"
set AppleScript's text item delimiters to return
set chFile to text items of thefile
set AppleScript's text item delimiters to ""
set n to count chFile
repeat with i from 1 to n
set rnFile to item i of chFile
set nwname to (do shell script "echo" & quoted form of rnFile & "| sed 's # stars_01_01 # stars_01_00 #'")
set endFile to (do shell script "mv -f" & quoted form of rnFile & "" & quoted form of nwname)
end repeat**
which is equivalent to the rename multiple files function of the Finder
Just a rough answer, why use terminal script?
You can just use the Finder with its rename function
by selecting the common part of all your files in your example "stars_01_01" and replacing it with "stars_01_00", this will lead to the same result without having to write a script with :
sed 's#stars_01_01#stars_01_00#g'

How to select line in AppleScript

I'm trying to figure out how to use Text Item Delimiters on a long line of text that is in a log file.
Within the log of information there is always a constant phrase that i'm searching for which leads me to the line of text. I'm getting to the line I want by searching for "[Constant]", for example.
The problem I'm having is that I can't select the whole line to perform a Delimiter. Below is a very basic example of what the log looks like.
qwertyuiop
mnbvcxza
oqeryuiiop
[Constant] 1234567890123456-098765432109876-8765432118976543
odgnsgnsanfadf
joiergjdfmgadfs
Any advice would be appreciated.
So far I'm using:
repeat 16 times
key code 124 using (shift down)
end repeat
Which does the job fine but it is clunky.
An easy way to find a line of text containing a specific string is the shell command grep.
set theConstant to "Constant"
set theText to "qwertyuiop
mnbvcxza
oqeryuiiop
Constant 1234567890123456-098765432109876-8765432118976543
odgnsgnsanfadf
joiergjdfmgadfs"
set foundLine to do shell script "echo " & quoted form of theText & " | tr '\\r' '\\n' | grep " & quoted form of theConstant
the tr part to replace return (0x0d) characters with linefeed (0x0a) characters is necessary to conform to the shell line separator requirements.
If the constant contains special characters it's a bit more complicated, because you have to escape the characters before passing them to the shell.
set theConstant to "\\[Constant\\]"
set theText to "qwertyuiop
mnbvcxza
oqeryuiiop
[Constant] 1234567890123456-098765432109876-8765432118976543
odgnsgnsanfadf
joiergjdfmgadfs"
set foundLine to do shell script "echo " & quoted form of theText & " | tr '\\r' '\\n' | grep " & quoted form of theConstant
If you want to read the text from a file on disk you can use this
set logFile to (path to library folder from user domain as text) & "Logs:myLogFile.log"
set theText to read file logFile as «class utf8»
Your question is puzzling. Do you want to parse a text/log file or a script to work with the GUI of some app? Because that is what your code suggests...
If you want to parse a log file, which is easier, you can use the good old Unix tools OSX comes with. You can use them from inside Applescript like this...
set logfile to "/some/path/file.log"
# Quote the string in case it contains spaces... or add single quotes above...
set qlogfile to quoted form of logfile
# Prepare the shell command to run
set cmd to "grep '^\\[Constant]' " & qlogfile & " | cut -c 12- | tr '-' '\\n'"
# Run it and capture the output
try
set cmdoutput to (do shell script cmd)
on error
# Oh no, command errored. Best we do something there
end try
The result looks like this...
tell current application
do shell script "grep '^\\[Constant]' '/some/path/file.log' | cut -c 12- | tr '-' '\\n'"
--> "1234567890123456
098765432109876
8765432118976543"
end tell
Result:
"1234567890123456
098765432109876
8765432118976543"
So to break it down the shell commands are,
grep ... | will read the contents of the file and select all lines that start ^ with the text [Constant] and pass what it finds | on to the next command
cut cuts out the characters from position 12 until the end - of the line
tr replaced any character - with \n which is the code for newline in unix.
The \\ you see are due to having it executed from inside Applescript. You only need on if you run it inside Terminal.
If you care to know the contents of one line from the other, then remove the last command | tr '-' '\\n' and it will return
Result:
"1234567890123456-098765432109876-8765432118976543"

expanding variables inside an Bash script that has a HEREDOC in AppleScript

I have this simple code:
#!/bin/bash
# Where are we going to store these files?
BACKUPSTORE="$HOME/Library/Application\ Support/Evernote-Backups"
/bin/echo "BACKUPSTORE: $BACKUPSTORE"
/bin/mkdir -p "$BACKUPSTORE"
/usr/bin/cd "$BACKUPSTORE"
osascript <<END
-- PURPOSE: Export all notes in Evernote to an ENEX file so that
-- the notes can be backed up to an external drive or to the cloud
-- Change the path below to the location you want the notes to be exported
set f to $BACKUPSTORE
with timeout of (30 * 60) seconds
tell application "Evernote"
-- Set date to 1990 so it finds all notes
set matches to find notes "created:19900101"
-- export to file set above
export matches to f
end tell
end timeout
-- Compress the file so that there is less to backup to the cloud
set p to POSIX path of f
do shell script "/usr/bin/gzip " & quoted form of p
END
I think I am getting an error on:
set f to $BACKUPSTORE
Or possibly on:
set p to POSIX path of f
do shell script "/usr/bin/gzip " & quoted form of p
How do I get the expansion to work, and deal with the spaces in the file path and using escaped spaces or literal quoting as AppleScript wants it?
The error I get in a shell when I ./run it is:
217:218: syntax error: Expected expression but found unknown token. (-2741)
You need to put quotes around the string:
set f to "$BACKUPSTORE"
You also don't need to escape the spaces when assigning to BACKUPSTORE, since you have the value in quotes.

Search folder for files with matching prefix and perform action in applescript

I have 10s of thousands of PDF files and I'd like to find ones that match certain characteristics and perform an action (merge into a PDF)
For example, I have files like:
filegroup1_abc.pdf
filegroup2_xyz.pdf
filegroup3_qrs.pdf
filegroup3_lmn.pdf
I'd like to find every file that has the same prefix, "filegroup1" and merge them into one PDF, then find the next match (filegroup2), then the next, etc...
So in my above example the last two would be merged as a new PDF since they have "Filegroup3" prefix.
I have found a script to merge PDFs using applescript; so my main question is how to search through the folder, find those files, then perform an action on them. However the pattern of "filetype1" is not known, so the script would first need to check every file and compare when the first X number of characters match in the filename. In this case it's the first 22 characters are identical and indicate a relationship between the files.
Also, I'm trying to do this in applescript but it might be easier to do with another method.
--choose working folder
set ff to quoted form of POSIX path of (choose folder)
try
--returns files matching names as return-delimited text, filter to list of "paragraphs"
-- using built-in AS object text awareness
[EDIT]
--OLD; incorrect:
--set allABCs to every paragraph of (do shell script "cd " & ff & ";" & "ls filegroup*_qrs.pdf")
-- new and improved:
set allABCs to every paragraph of (do shell script "cd " & ff & ";" & "ls filegroup1_???.pdf")
--that matches only 3-character strings. The following
-- matches any number of characters between _ and .pdf:
--set allABCs to every paragraph of (do shell script "cd " & ff & ";" & "ls filegroup1_*.pdf")
on error--it's in a try because if you mistakedly look for files that aren't there,
-- it will return an error. As an aside, doing 'ls' and getting folders
-- returns extra empty strings -- just a cautionary note that probably doesn't matter here
return {}
end try
--and one more caution which you may not need -- you may need to sort results to order the files correctly, if that matters to you

Script to convert lower case characters into upper case is working differently as service action

I am trying a simple script as a service action in automator which performs this function:
Receives selected text in any application and replaces selected text
with the text containing capital letters
So I used this script:
on run {input, parameters}
set upperCaseString to ""
repeat with i in input
if (ASCII number i) > 96 and (ASCII number i) < 123 then
set upperCaseString to upperCaseString & (ASCII character ((ASCII number i) - 32))
else
set upperCaseString to upperCaseString & (ASCII character (ASCII number i))
end if
end repeat
return upperCaseString
end run
But I found this problem:
It was returning first letter of input as an upper case letter, eg.
input - lowercasetext, output - L, whereas the expected output was -
LOWERCASETEXT.
To check the problem I added this line of code in repeat loop:
display dialog i
and found that it is displaying complete text in place of single character at a time ,ie. in place of displaying l.. o.. w.. in lowercasetext it is displaying lowercasetext at once.
Can anyone suggest me why is it bugging me as service action while it is working fine in Apple Script Editor?
This works for a lot of languages:
on toUpper(s)
tell AppleScript to return do shell script "shopt -u xpg_echo; export LANG='" & user locale of (system info) & ".UTF-8'; echo " & quoted form of s & " | tr [:lower:] [:upper:]"
end toUpper
on toLower(s)
tell AppleScript to return do shell script "shopt -u xpg_echo; export LANG='" & user locale of (system info) & ".UTF-8'; echo " & quoted form of s & " | tr [:upper:] [:lower:]"
end toLower
When I run your script, I get the correct result. But one thing you may want to do is to explicitly coerce your result to text. The easiest way to do that would be at the end:
return upperCaseString as text
That may or may not do it for you, but you'll avoid a lot of frustration if you explicitly coerce data when there is a possibility of ambiguity.
Another (faster) way is to leverage the Unix tr (translate) command the via do shell script:
set upperCaseString to ¬
(do shell script ("echo " & input & " | tr a-z A-Z;"))
That's enough for 'English' language, but you can also add diacritical translation, like so
set upperCaseString to ¬
(do shell script ("echo " & input & " | tr a-zäáà A-ZÄÁÀ;"))
tr will translate anything to anything, so you can add any characters you may encounter and what you'd like them to translate to. A 'leet-speak' translator comes to mind.
You will get the same result in the AppleScript Editor if the input variable is set to a list. The input parameter of an Automator action is also a list, so your comparison isn't doing what you think. Note that text id's have obsoleted ASCII character and ASCII number commands - see the 10.5 AppleScript Release notes.
#Matt Strange:
You could also try:
set upperCaseString to ¬
do shell script "echo " & input & " | tr [:lower:] [:upper:]"
If you run 'man tr' on 'OS X 10.10' you may see that the character classes [:lower:] and [:upper:] should be used instead of explicit character ranges like 'a-z' or 'A-Z', since these may not produce correct results as it is explained there, on the manual page.

Resources