How to find all available fonts on OSX using the default shell - bash

I'm trying to write a script for Adobe After Effects using extendscript (a proprietary ECMAScript dialect, but mostly ≈ javascript). I can use an inbuilt command system.callSystem() to execute a command using the default(?) shell, but I can't find a bash one liner, or an AppleScript command I can use to list the available fonts.
Is there a way of getting all the fonts on the command line in OSX?

From AppleScript, you can use this ASOC code to get the names of all of the fonts or font families available to the system:
use framework "AppKit"
set fontFamilyNames to (current application's NSFontManager's sharedFontManager's availableFontFamilies) as list
set fontNames to (current application's NSFontManager's sharedFontManager's availableFonts) as list
I'm not sure which of those you want, so I included code for both. If you want to access this script from bash, use the osascript command:
fontFamilyNames=$(osascript << SCPT
use framework "AppKit"
set fontFamilyNames to (current application's NSFontManager's sharedFontManager's availableFontFamilies) as list
return fontFamilyNames
SCPT)

Solution 1: AppleScript
tell application "Font Book" to set activeFontsList to name of every font family --- whose enabled is true
Note that the whose enabled is true filter is commented out because it slows down the query considerably.
Solution 2: AppleScript & Bash
You can execute the AppleScript above from Bash like that:
#!/usr/bin/env bash
# Query the list of fonts with AppleScript.
font_list=$(osascript << SCPT
tell application "Font Book" to set activeFontsList to name of every font family --- whose enabled is true
SCPT)
# Convert the list to column and sort it.
font_list=$(echo $font_list | awk -e 'gsub(", ", "\n")' | sort -f)
# Display the list.
echo -e "$font_list"
# Display the list size.
echo -e "$font_list" | wc -l | xargs printf "\nFont count: %d\n"
Same script but one-liner:
font_list=$(osascript -e 'tell application "Font Book" to set activeFontsList to name of every font family --- whose enabled is true') && font_list=$(echo $font_list | awk -e 'gsub(", ", "\n")' | sort -f) && echo -e "$font_list"
Solution 3: fc-list
fc-list : family | sort -f
fc-list : family | wc -l | xargs printf "\nFont count: %d\n"
You will find some examples here: https://www.geeksforgeeks.org/fc-list-command-in-linux-with-examples/.

Related

How to trim a string in shell script with a specific pattern?

How's everyone doing?
So, if I run xdotool getactivewindow getwindowname, it gives the full title of the current window, for example:
fish home/kibe/Documents — Konsole
Blablablabla - Stack Overflow - Google Chrome
The thing is, I only want the application name (Konsole and Google Chrome).
I can easily do it in Python, as such:
def getAppTitle (fullStr):
lastDashIndex = None
for i in range(len(fullStr)):
if fullStr[i] == '-' or fullStr[i] == '—':
lastDashIndex = i
return fullStr[lastDashIndex+2:] if lastDashIndex else fullStr
print(getAppTitle('blablabla - blablabla - ApplicationName'))
# returns ApplicationName
I have been trying to do the same in shell script but I can't do it for the life of me. Also, for some reasons, some applications use "-" (normal dash) and others "—" (em dash).
How can I do that in shell?
You have to use this 'em dash' or dash as the field separator and print the last field:
xdotool getactivewindow getwindowname | awk -F"—|-" '{print $NF}'
I am not sure where this 'em dash' comes from, I had to copy paste it for the above command.
Maybe better, use two characters as the FS, any dash and a space, to get the same as your script, with the space trimmed.
xdotool getactivewindow getwindowname | awk -F"— |- " '{print $NF}'

If string does NOT contain and REGEX

I'm looking for a way to write the following javascript code in applescript: If the condition is false then I want to do something.
var regEx = /\d{5}/g;
var str = 'This string contains 12345';
if (!regEx.test(str)){
do something
}
Below is the applescript I started but it doesn't work.
set str to 'This string contains 12345'
set regEx to <NOT SURE HOW APPLESCRIPT HANDLES THIS>
if string does contains "12345" then
do something
end if
In Javascript ! = does not. What is the equivalent in applescript? and how do I handle RegEx?
My overall goal is to find out if the finder window selected DOES NOT contain any 5 digit number combination in the folder name.
tl;dr For any version of macOS that is >= OSX 10.8 you'll need to replace grep's -P option (as indicated in the "Solution" section below) with the -E option - as mentioned in the "Different grep utilities" section at the bottom of this post.
As correctly noted in the comments...
Vanilla AppleScript can't handle regex. - vadian
so you'll need to
shell out to something that does know regex - red_menace
Solution:
To meet your requirement with vanilla AppleScript in a way which is analogous to JavaScript's test() method, consider utilizing a custom AppleScript subroutine as follows:
Subroutine:
on regExpTest(str, re)
set statusCode to do shell script "grep -q -P " & quoted form of re & ¬
" <<<" & quoted form of str & " 2>/dev/null; echo $?"
if statusCode is equal to "0" then
return true
else
return false
end if
end regExpTest
Usage:
set regExp to "\\d{5}"
set str to "This string contains 12345"
if regExpTest(str, regExp) then
display dialog "It DOES match so let's do something"
end if
Running the above script will display a dialog with the given message because there is a match between the regular expression and the specified string.
Note: AppleScript strings use the backslash as an escape character, so you'll notice that the \d metacharacter has been further escaped with an additional backslash, i.e. \\d
Inequality operators:
In Javascript != does not. What is the equivalent in applescript? and how do I handle RegEx?
AppleScript's inequality operators that are analogous to JavaScripts inequality operator (!=) are:
≠
is not
isn't
isn't equal [to]
is not equal [to]
doesn't equal
does not equal
So given your JavaScript if statement:
if (!regEx.test(str)){
// do something
}
We can achieve the same logic, (again using the aforementioned custom regExpTest subroutine), with the following code:
set regExp to "\\d{5}"
set str to "This string contains 1234"
if regExpTest(str, regExp) ≠ true then
display dialog "It DOES NOT match so let's do something"
end if
Note The str value only includes four consecutive digits, i.e. 1234.
This time running the above script will display a dialog with the given message because there is NOT a match between the regular expression and the specified string.
There are many variations that can be made to the aforementioned AppleScript if statement to acheieve the same desired logic. For example;
if regExpTest(str, regExp) is not equal to true then
...
end if
if regExpTest(str, regExp) = false then
...
end if
etc...
regExpTest subroutine explanation:
The aforementioned regExpTest AppleScript subroutine is essentially utilizing the do shell script command to run the following code that you would run directly via your macOS Terminal application. For instance in your Terminal application run the following two commands:
grep -q -P "\d{5}" <<<"This string contains 12345" 2>/dev/null; echo $?
Prints:
0
grep -q -P "\d{5}" <<<"This string contains 1234" 2>/dev/null; echo $?
Prints:
1
EDIT: Different grep utilities:
As noted in the comment by user3439894 it seems that some versions of the grep utility installed on Mac do not support the -P option which ensured the RegExp pattern was interpreted as a Perl regular expression. The reason why I opted to utilize a Perl Regular Expression is because they're more closely aligned to the regexp's used in JavaScript.
However, If you run man grep via your command line and discover that your greputility doesn't provide the -P option then change the following line of code in the regExpTest subroutine:
set statusCode to do shell script "grep -q -P " & quoted form of re & ¬
" <<<" & quoted form of str & " 2>/dev/null; echo $?"
to this instead:
set statusCode to do shell script "grep -q -E " & quoted form of re & ¬
" <<<" & quoted form of str & " 2>/dev/null; echo $?"
Note: The -P option has been changed to -E so the pattern is now interpreted as an extended regular expression (ERE) instead.
The shorthand metacharacter \d
You may also find that you need to change the the assignment of the regexp pattern from:
set regExp to "\\d{5}"
to
set regExp to "[0-9]{5}"
This time the shorthand metacharacter \d, (which is used match a digit), has been replaced with the equivalent character class [0-9].
As others have said, you can use the Foundation framework’s NSRegularExpression via the AppleScript-ObjC bridge.
That said, Objective-C APIs, while powerful, aren’t exactly AppleScripter-friendly, so I knocked together some “standard libraries” a few years back that wrapped a lot of that general functionality as nice native AppleScript commands.
e.g. Here’s the nearest equivalent to your JavaScript using the Text library’s search text command:
use script "Text"
set str to "This string contains 12345"
set foundMatches to search text str for "\\d{5}" using pattern matching
if foundMatches is not {} then
-- do something
end if
Couldn’t drum up much interest so I no longer do development or support. But they’re free and open (public domain as far as I’m concerned) and still work fine in the current version of macOS AFAIK, so help yourself.

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.

UNIX Terminal dialog , that supports item selection

Is there any "dialog" that running inside a TTY or x-terminal ? I wanted to make some select operation , e.g configure system service , whether or not should it start at boot time.
I'm not planning to use ncurses library myself , it's better to work with bash script.
Expected item selection:
---------------------
Item []
Item []
----------------------
Use arrow keys to iterate through those items , and use space to alternate selection of current item , i remeber seeing similar things in RedHat , just not so clear of the command and library.
Thanks !
Maybe dialog --checklist is what you want?
My smenu (https://github.com/p-gen/smenu) tool can do this:
R=$(echo "'Item 1'\\n'Item 2'" | smenu -d -T, -l)
echo $R
(use the t command to tag/un-tag an item)
Maybe what you want is read.
Check this: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html

AppleScript how to get current display resolution?

I'm trying to get the current display resolution of both of my displays depending on where the mouse cursor is.
i.e. when the mouse cursor is on the first display I want to get the resolution of this display.
With a shell script I can get both resolutions:
set screenWidth to (do shell script "system_profiler SPDisplaysDataType | grep Resolution | awk '{print $2}'")
But I don't get which display is currently "active".
Any ideas?
This does the trick:
tell application "Finder"
set screen_resolution to bounds of window of desktop
end tell
Applescript does not have any access to cursor location, even via System Events. Sorry.
[There are a couple commercial solutions, but I'm guessing they're not worth the trouble in this case? I suppose I could also whip up a quick command-line tool that just returns the current cursor location... worth the trouble?]
p.s. awk is great at finding matching lines:
set screenWidth to (do shell script "system_profiler SPDisplaysDataType | awk '/Resolution/{print $2}'")
For the sake of even more completeness, here is the code to get the width, height, and Retina scale of a specific display (main or built-in).
This is the code to get the resolution and Retina scale of the built-in display:
set {width, height, scale} to words of (do shell script "system_profiler SPDisplaysDataType | awk '/Built-In: Yes/{found=1} /Resolution/{width=$2; height=$4} /Retina/{scale=($2 == \"Yes\" ? 2 : 1)} /^ {8}[^ ]+/{if(found) {exit}; scale=1} END{printf \"%d %d %d\\n\", width, height, scale}'")
And this is the code to get the resolution and Retina scale of the main display:
set {width, height, scale} to words of (do shell script "system_profiler SPDisplaysDataType | awk '/Main Display: Yes/{found=1} /Resolution/{width=$2; height=$4} /Retina/{scale=($2 == \"Yes\" ? 2 : 1)} /^ {8}[^ ]+/{if(found) {exit}; scale=1} END{printf \"%d %d %d\\n\", width, height, scale}'")
The code is based on this post by Jessi Baughman and the other answers given here.
The following does not solve the OP's problem, but may be helpful to those wanting to determine the resolution of ALL attached displays in AppleScript (thanks to #JoelReid and #iloveitaly for the building blocks):
set resolutions to {}
repeat with p in paragraphs of ¬
(do shell script "system_profiler SPDisplaysDataType | awk '/Resolution:/{ printf \"%s %s\\n\", $2, $4 }'")
set resolutions to resolutions & {{word 1 of p as number, word 2 of p as number}}
end repeat
# `resolutions` now contains a list of size lists;
# e.g., with 2 displays, something like {{2560, 1440}, {1920, 1200}}
For the sake of completeness, here is the code to grab the screen height:
do shell script "system_profiler SPDisplaysDataType | awk '/Resolution/{print $4}'"}
Multi-Monitor and Retina detection
To get the width, height and scaling (retina = 2, else = 1) for all monitors:
set resolutions to {}
repeat with p in paragraphs of ¬
(do shell script "system_profiler SPDisplaysDataType | awk '/Resolution:/{ printf \"%s %s %s\\n\", $2, $4, ($5 == \"Retina\" ? 2 : 1) }'")
set resolutions to resolutions & {{word 1 of p as number, word 2 of p as number, word 3 of p as number}}
end repeat
get resolutions
Based on answers above.
Results in something like this:
{{2304, 1440, 2}, {1920, 1080, 1}}
On my machine system_profiler takes nearly a second to return a reply. For my purposes, that way too long.
Pre-10.12, I used ASObjC Runner but apparently that no longer works.
This is much faster for me:
tell application "Finder" to get bounds of window of desktop
(Taken from https://superuser.com/a/735330/64606)
I have a shell script that makes use of cliclick and displayplacer, both available in Homebrew: https://github.com/huyz/trustytools/blob/master/mac/get-bounds-of-mouse-display.sh
To use from within AppleScript:
set displayBounds to do shell script "PATH=/opt/homebrew/bin:$PATH /Users/huyz/bin/get-bounds-of-mouse-display | xargs -n 1 echo"
set displayBounds to the paragraphs of displayBounds

Resources