Assign pathnames returned from bash command(s) to an AppleScript list

≡放荡痞女 提交于 2021-01-29 11:19:40

问题


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:

  1. 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 to stdout will be text - 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.

  2. The second line reading:

    set latestList to transformStdoutToList(stdout)
    

    invokes the transformStdoutToList subroutine passing in the value of stdout and assigns the result returned to the variable named latestList. The class of the value assigned to latestList will be list. Again, you can verify this by temporarily adding the following line to the script:

    log class of latestList
    
  3. The transformStdoutToList subroutine transforms each line (i.e. a pathname) that is passed to it and forms a new list 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:

  1. Select AppleScript Editor > Preferences... from the menu bar.
  2. Select the Editing tab.
  3. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!