问题
I want to prompt the paths of the 10 recently added files of a directory (recursively) in Applescript as a list. This works fine in bash:
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
array=(`find . -type f -print0 | xargs -0 ls -t | head -n 10`)
echo "${array[*]}"
IFS=$SAVEIFS
I’d like to store the resulting array in an Applescript Variable:
set l to (do shell script "______________")
How can I put the bash part into a working 1-liner? Maybe there is also an Applescript-only solution?
回答1:
When you "shell out" from AppleScript the class
of the value that you assign to a variable, (i.e. the variable named l
in your example), will always be text and not a list.
In your scenario you're essentially capturing the pathname(s) that the find utility etc send to stdout
(fd 1) which Applescript just recognizes as text
.
To convert each line (i.e. a pathname that is printed to stdout
via your bash commands) you'll need to utilize a helper subroutine/function as shown in the following gist.
set stdout to do shell script "/usr/bin/find " & quoted form of "/absolute/path/to/target/directory" & " -type f -print0 | xargs -0 ls -t | head -n 10"
set latestList to transformStdoutToList(stdout)
-- Test it's a proper AppleScript list.
log class of latestList
log (item 1 of latestList)
log (item 2 of latestList)
-- ...
(**
* Transforms each line printed to stdout to form a new list of pathnames.
*
* Pathname(s) may contain newline `\n` characters in any part, including
* their basenames. Below we read each line, if it begins with a forward
* slash `/` it is considered to be the start of a pathname. If a line does
* not begin with a forward slash `/` it is considered to be part of the
* prevous pathname. In this scenario the line is appended to previous item
* of the list and the newline character `\n` is reinstated.
*
* @param {String} pathsString - The pathname(s) printed to stdout.
* @return {List} - A list whereby each item is a pathname.
*)
on transformStdoutToList(pathsString)
set pathList to {}
repeat with aLine in paragraphs of pathsString
if aLine starts with "/" then
set end of pathList to aLine
else
set last item of pathList to last item of pathList & "\n" & aLine
end if
end repeat
return pathList
end transformStdoutToList
Explanation:
In the first line reading:
set stdout to do shell script "/usr/bin/find " & quoted form of "/absolute/path/to/target/directory" & " -type f -print0 | xargs -0 ls -t | head -n 10"
- we utilize AppleScript's do shell script command to execute your bash commands.
Assign the result of the bash commands (which is typically a multi-line string of pathnames) to the AppleScript variable named
stdout
. The class of the value assigned tostdout
will betext
- you can verify this by temporarily adding the following line to the script:log class of stdout
Note: You'll need to redefine the part that currently reads;
/absolute/path/to/target/directory
, with a real absolute path to the directory/folder that you want to search. You'll also notice that this target pathname is preceded with& quoted form of
- this just ensures any space character(s) in the given pathname are interpreted correctly.
The second line reading:
set latestList to transformStdoutToList(stdout)
invokes the
transformStdoutToList
subroutine passing in the value ofstdout
and assigns the result returned to the variable namedlatestList
. The class of the value assigned tolatestList
will belist
. Again, you can verify this by temporarily adding the following line to the script:log class of latestList
The
transformStdoutToList
subroutine transforms each line (i.e. a pathname) that is passed to it and forms a newlist
of pathname(s). Please read the comments in the code above for further explanation - you'll notice that is successfully handles any pathname(s) that may include newline character(s).
Additional Note:
The aforementioned transformStdoutToList
subroutine includes a line that reads:
set last item of pathList to last item of pathList & "\n" & aLine
The "\n"
part exists to reinstate any newline characters that may exist in a pathname. However when you compile the script in the AppleScript Editor this will appear as follows:
set last item of pathList to last item of pathList & "
" & aLine
Note: the newline character, i.e. the \n
part, has disappeared and has created an actual line-break.
This is normal and the script will produce the expected result. However, if you want to preserve the "\n"
part in your AppleScript Editor then please change your preferences as described below:
- Select
AppleScript Editor
>Preferences...
from the menu bar. - Select the
Editing
tab. - Click the checkbox for the
Formatting: Escape tabs and line breaks in strings
(i.e. switch this option on).
Edit:
How can I put the bash part into a working 1-liner
If you must have a "1-liner" and are willing to sacrifice readability then you could do something like this instead:
set l to transformStdoutToList(do shell script "/usr/bin/find " & quoted form of "/absolute/path/to/target/directory" & " -type f -print0 | xargs -0 ls -t | head -n 10")
However, you'll still need to utilize the aforementioned transformStdoutToList
subroutine, so that will need to be present in your script too.
来源:https://stackoverflow.com/questions/56358282/assign-pathnames-returned-from-bash-commands-to-an-applescript-list