#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
viapowershell -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)"