Как записать содержимое RTF-файла в буфер обмена Windows с помощью однострочного?

#powershell

#powershell

Вопрос:

Я практически ничего не знаю о PowerShell, но мне нужно выполнить очень конкретную задачу: разработать однострочник для записи содержимого RTF-файла в буфер обмена Windows.

У меня есть отдельные части, которые работают, но мне не хватает знаний синтаксиса, чтобы соединить все это вместе.

Этот небольшой скрипт работает, если его сохранить blah.ps1 , а затем вызвать как ./blah.ps1 , но мне нужно избегать использования скрипта.

 $data = New-Object System.Windows.Forms.DataObject
$rtf = Get-Content -Path foo.rtf -Raw
$data.SetData([System.Windows.Forms.DataFormats]::Rtf, $rtf)
[System.Windows.Forms.Clipboard]::SetDataObject($data)
 

Но мне нужно выразить это как однострочную строку примерно так:

 Get-Content foo.rtf | $data = New-Object System.Windows.Forms.DataObject; $data.SetData([System.Windows.Forms.DataFormats]::Rtf, $_); [System.Windows.Forms.Clipboard]::SetDataObject($data)
 

что приводит к сбою с

 At line:1 char:24
  Get-Content foo.rtf | $data = New-Object System.Windows.Forms.DataOb ...
                         ~~~~~
Expressions are only allowed as the first element of a pipeline.
      CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
      FullyQualifiedErrorId : ExpressionsMustBeFirstInPipeline
 

Комментарии:

1. Почему бы просто Get-Content foo.rtf | Set-Clipboard

2. Потому что это помещает необработанный RTF в текстовую часть буфера обмена.

3. Ах, хорошо. Спасибо

4. pbcopy в macOS автоматически определяет заголовок RTF и помещает его в правильную картонную коробку, но, увы Set-Clipboard , похоже, этого не делает.

Ответ №1:

Точки с запятой ( ; ) используются для имитации перевода строки в однострочных сценариях, символы канала ( | ) используются для передачи выходных данных по конвейеру в качестве входных данных, вы можете превратить это в однострочный файл, который не нуждается ни в том, ни в другом, просто обернув их друг в друга:

 [Windows.Forms.Clipboard]::SetDataObject([Windows.Forms.DataObject]::new([Windows.Forms.DataFormats]::Rtf,(Get-Content -Raw "C:pathtofile.rtf")))
 

Вероятно, вам также потребуется «Добавить» формы, поэтому, если это не сработает:

 Add-Type -AssemblyName "System.Windows.Forms"|Out-Null;[Windows.Forms.Clipboard]::SetDataObject([Windows.Forms.DataObject]::new([Windows.Forms.DataFormats]::Rtf,(Get-Content -Raw "C:pathtofile.rtf")))
 

Комментарии:

1. Первое предложение просто работает! Фантастика.

2. дженнибрайн… Мне всегда интересно, почему люди выбирают тот путь, который они выбирают. Почему это должно быть однострочным ? Если вы делаете это в интерактивной консоли PowerShell или тому подобном, я понимаю это, но в скрипте… ну, ты знаешь . Существует несколько документированных способов обработки вашего варианта использования, подобных тому, который был отмечен colsw.

3. Это обеспечивает полу-поддерживаемую, второстепенную функцию пакета R, и мне нужно выложиться, чтобы получить этот RTF-файл в буфере обмена. Не так просто отправить сценарий PowerShell внутри пакета, отсортировать его путь и разобраться с настройкой политики выполнения. Но если вы думаете, что мне не хватает какого-то другого решения, я буду рад узнать больше. Как я уже сказал, я довольно плохо разбираюсь в PowerShell.

4. Для записи, при фактическом использовании, мне действительно нужно было «Добавить» System.Windows.Forms сборку. На самом деле я должен вызывать это из cmd.exe via powershell -Command "..." , а не в интерактивном экземпляре PowerShell. RTF-часть буфера обмена также сохраняется только на время работы экземпляра PowerShell, что является еще одной проблемой.

Ответ №2:

Теперь я использовал очень полезное предложение @colsw, чтобы найти лучшее решение. Одним из недостатков моего исходного кода является то, что RTF сохраняется в буфере обмена только до завершения работы экземпляра PowerShell. Это не проблема во время интерактивной разработки, но в моем реальном использовании это было проблемой. Обновление: теперь я знаю, что вы можете вызвать SetDataObject метод в $true качестве второго аргумента ( copy аргумент), чтобы сохранить данные буфера обмена.

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

(Если бы я действительно хотел сценарий, я бы не стал жестко устанавливать путь к файлу RTF таким образом, но в моем реальном случае использования мне приходится интерполировать имя файла во время выполнения.)

Здесь это в виде скрипта:

 Add-Type -AssemblyName System.Windows.Forms
$rtf = Get-Content -Path foo.rtf
[Windows.Forms.Clipboard]::SetText($rtf, [System.Windows.Forms.TextDataFormat]::Rtf)
 

И как уродливый однострочный:

 powershell -Command "Add-Type -AssemblyName System.Windows.Forms | Out-Null;[Windows.Forms.Clipboard]::SetText((Get-Content foo.rtf),[Windows.Forms.TextDataFormat]::Rtf)"