У меня есть скрипт Python 2.7.10, который принимает вводимые пользователем данные и вставляет их в параметр name и body в make new note AppleScript.

Проблема в том, что любые escape-символы или специальные символы интерпретируются AppleScript. Я хочу, чтобы все строки обрабатывались как необработанные и игнорировали все escape-символы и такие вещи, как :\//tft// или c:\test\test.txt, не сообщая мне об ошибке Expected “"” but found unknown token. или игнорируя символ t после \

Строка Python выглядит так:

cmd = "osascript -e 'tell application \"Notes\" \n tell account \"iCloud\" \n make new note at folder \"Notes\" with properties {name:\"%s\", body:\"%s\"} \n end tell \n end tell'" % (header, body)

... где header и body - предоставленные пользователем строки.

Но для ручного тестирования я использую Script Editor, чтобы быстро воспроизвести ошибку.

tell application "Notes"
  tell account "iCloud"
    make new note at folder "Notes" with properties {name:"myname", body:"c:\test\test.txt"}
  end tell
end tell

Эта конкретная заметка в итоге выглядит так:

enter image description here

Я знаю, что могу использовать \\ вместо \, но я не хочу, чтобы пользователям приходилось очищать все свои входные данные, поскольку они могут копировать вставки из большого объема текста. Подумайте о файле журнала или тексте в виде вставки в корзину.

Есть ли способ программной дезинфекции ввода пользователя?

< Сильный > Примечание :

Это НЕ дубликат этого вопроса, потому что я попытался заменить строковую переменную header и body на eval(header) и eval(body), но это не сработало. Я также пытался .decode('string_escape') безрезультатно. В конце концов, я тоже попытался:

d = header.escape('\w[0-9]')
header = d.decode('string_escape')

Я думаю, что это связано со способностью AppleScript принимать эту строку, а не только со способностью Python очищать ее с помощью вышеуказанных функций.

< Сильный > UPDATE

Я собираю пользовательский ввод, используя диалоговое окно с кодом, подобным этому:

cmd = "osascript -e \'set theString to text returned of (display dialog \"Please Enter The Note To Add To Your iCloud Notes \" with icon file \"%s\" default answer \"\n\n\n\" buttons {\"OK\",\"Cancel\"} default button 1) \'"  % (appicon_abs_path_apple)
note = run_script(cmd)
0
frakman1 30 Июн 2019 в 23:49

3 ответа

Лучший ответ

В приведенном ниже списке demo.py есть пользовательская функция sanitize, которая используется для экранирования любых символов (") обратной косой черты ("), которые пользователь может войти в диалоговое окно. Эти символы необходимо экранировать таким образом в вашем .py файле, прежде чем впоследствии передать их osascript.

< Сильный > demo.py

#!/usr/bin/env python

from subprocess import Popen, PIPE


def sanitize(str):
    return str.replace("\\", "\\\\") \
              .replace("\"", "\\\"")


def run_script(script):
    p = Popen(['osascript', '-'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    stdout, stderr = p.communicate(script)
    return stdout

appicon_abs_path_apple = "Applications:Stickies.app:Contents:Resources:Stickies.icns"

input_dialog = """
tell application "Finder"
  activate
  set mssg to "Please Enter The Note To Add To Your iCloud Notes"
  set theString to text returned of (display dialog mssg with icon file "%s" \
      default answer "\n\n\n" buttons {"OK", "Cancel"} default button 1)
end tell
""" % (appicon_abs_path_apple)

# Notice in the following line we `sanitize` the text characters returned
# from the input dialog before assigning it to the `note` variable.
note = sanitize(run_script(input_dialog))

# -------------------------------

# Let's test that any special characters have been preserved
show_input = """
tell application "Finder"
  activate
  display dialog "%s"
end tell
""" % (note)

run_script(show_input)

< Сильного > Примечание :

Части show_input и run_script(show_input) в конце demo.py предназначены только для тестирования. Это должно быть заменено кодом AppleScript, необходимым для создания новой заметки. Например:

# ...
# ...

note = sanitize(run_script(input_dialog))

# header = sanitize(header)

make_note = """
tell application "Notes"
  tell account "iCloud"
    make new note at folder "Notes" with properties {name:"%s", body:"%s"}
  end tell
end tell
""" % (header, note)

run_script(make_note)

Возможно, вы также захотите передать текстовую строку, назначенную переменной header, через функцию sanitize (согласно строке, закомментированной в приведенном выше фрагменте кода), однако я не уверен в вашем вопросе откуда эти данные Если это сгенерированный пользователем, то определенно sanitize.

Также обратите внимание, как в вышеупомянутой сущности мы заключаем код Applescript в тройные двойные кавычки (""") - это помогает сделать код более читабельным и избавляет от необходимости дополнительного экранирования и \n символов (символов), в отличие от следующего:

make_note = "osascript -e 'tell application \"Notes\" \n tell account \"iCloud\" \n make new note at folder \"Notes\" with properties {name:\"%s\", body:\"%s\"} \n end tell \n end tell'" % (header, body)

Демо-версия :

Чтобы проверить приведенную выше demo.py сущность, вам необходимо:

  1. Убедитесь, что файл исполняемый, выполнив что-то вроде chmod и изменив команду путь к файлу по необходимости.
chmod +x /some/path/to/demo.py
  1. Кроме того, вы, вероятно, захотите изменить путь к HFS (то есть путь, разделенный двоеточиями), который назначен переменной appicon_abs_path_apple - в настоящее время он использует значок для приложения Stickies.

< Сильный > Ввод :

В диалог введена следующая произвольная текстовая строка, содержащая специальные символы:

:\//tft//
c:\test\test.txt
c:\\quux\\foo.md
'¡"€#¢∞§¶•ª⁄™‹›fifl‡°·

Screenshot showing input text

Снимок экрана (выше), показывающий вводимый текст, содержит много специальных символов.

< Сильный > Вывод :

Screenshot showing that the input text is preserved after osascript

Снимок экрана (выше), показывающий, что специальные символы во входном тексте были сохранены в следующем диалоговом окне.

1
RobC 2 Июл 2019 в 16:12

Вот как можно параметризировать запуск AppleScript через osascript:

#!/usr/bin/env python

import subprocess

header ='my name'
body = 'some text'

subprocess.call(['osascript', 
    '-e', 'on run {theHeader, theBody}',
    '-e', ' tell application "Notes"',
    '-e', '  tell account "iCloud"',
    '-e', '   make new note at folder "Notes" with properties {name:theHeader, body:theBody}',
    '-e', '  end tell',
    '-e', ' end tell',
    '-e', 'end run', '--', header, body])

Для передачи более сложных данных рассмотрите py-applecript или PyObjC + AppleScript-ObjC.

0
foo 2 Июл 2019 в 10:38

Мне кажется, что это вопрос Python больше, чем вопрос AppleScript. Я имею в виду, если вы запрашивали основной текст через AppleScript, используя, скажем:

display dialog "Enter Note" default answer ""

AppleScript будет автоматически экранировать любые проблемные символы (то есть, если они введут c:\test\test.txt, результатом этой диалоговой команды отображения будет c:\\test\\test.txt). Мне кажется, вы получаете текст из какого-то другого источника и используете python для отправки его через AppleScript. Это означает, что вы должны избежать всего этого в python перед отправкой в osascript.

Аналитически достаточно легко убежать: замените каждый обратный слеш двойным. В Python я думаю, что это будет что-то вроде:

body.replace('\','\\')

В зависимости от того, какой текст вы получаете, вам может понадобиться немного его настроить. Например, если у вас есть лысые двойные кавычки, вам нужно их избежать:

body.replace('"','\"')

И если в текст встроены табуляции, возврат каретки или перевод строки (\ t, \ r, \ n), вам, возможно, придется найти какой-то способ избежать экранирования (вы можете надо копаться в регулярных выражениях для этого). Но идея состоит в том, чтобы сначала поместить escape-коды AppleScript в python, а затем вызвать команду osacript.

< Сильный > EDIT :

Теперь, когда я знаю, что вы получаете текст пользователя от display dialog, я собираюсь предложить вам вырезать посредника Python и обработать все это в AppleScript. Сценарий, который вы хотите это:

set txt to text returned of (display dialog "Please Enter The Note To Add To Your iCloud Notes" default answer "\n\n\n")
tell application "Notes"
    tell account "iCloud"
        make new note at folder "Notes" with properties {name:"myname", body:txt}
    end tell
end tell

Вы можете сохранить это как файл сценария и вызвать его из osascript - osascript scriptName.scpt - или вы можете ввести его непосредственно в osascript, используя последовательные опции -e:

osascript -e 'set txt to text returned of (display dialog "Please Enter The Note To Add To Your iCloud Notes" default answer "\n\n\n")' -e 'tell application "Notes"' -e 'tell account "iCloud"' -e 'make new note at folder "Notes" with properties {name:"myname", body:txt}' -e 'end tell' -e 'end tell'

Если вам нужно передать аргументы в скрипт (например, переменную для имени пользователя или путь к иконке), вам нужно использовать явный обработчик выполнения. Посмотрите «man osascript» или спросите, и я покажу вам, как.

1
Ted Wrigley 1 Июл 2019 в 18:14