Невозможно использовать sed при использовании ssh с ms powershell для хоста Linux

Это работает в Linux

sed "s/#\?\(PasswordAuthentication\s*\).*$/\1 no/" /etc/ssh/sshd_config;

Но в MS Powershell в Windows, когда я использую

pwsh -c ssh [email protected] -p 22 sed "s/#\?\(PasswordAuthentication\s*\).*$/\1 no/" /etc/ssh/sshd_config;

Я получаю следующую ошибку

sed: -e выражение №1, символ 35: незавершенная команда `s'

Прежде чем я исправлю проблему с кодировкой в ​​PowerShell, \1 выглядит правильно. Так что пока я не могу это решить.

$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding

Имя тела: utf-8
Имя кодировки: Юникод (UTF-8)
Имя заголовка: utf-8
Веб-имя: utf-8
WindowsCodePage: 1200
IsBrowserDisplay: True
IsBrowserSave: Правда
IsMailNewsDisplay: Верно
IsMailNewsSave: Верно
IsSingleByte: Ложь
EncoderFallback: System.Text.EncoderReplacementFallback
DecoderFallback: System.Text.DecoderReplacementFallback
IsReadOnly: Правда
Кодовая страница: 65001

Изменить дополнительную информацию

Есть ли проблема с SSH в PowerShell?

Я вижу, что команда изменена в информации об отладке.

Ошибка говорит, что опция «-e» не работает. В выражении sed есть знак доллара, который и вызывает проблему. Замените двойные кавычки одинарными, чтобы знак доллара воспринимался как символ, а не как имя переменной. sed может использовать любой символ в качестве начала/конца строки. Поэтому вместо кавычек можно использовать угловые скобки. Но здесь необходимо использовать одинарные кавычки, чтобы PS не заменял знак доллара.

jdweng 30.06.2024 12:33

@jdweng, хотя это правда, что нужно помнить об интерпретации $ PowerShell в строках "...", в данном случае это не проблема, потому что $, за которым не следует подвыражение или имя переменной, сохраняется как есть. Таким образом, использование '...' в данном случае не имеет значения, потому что "s/#\?\(PasswordAuthentication\s*\).*$/\1 no/" -eq 's/#\?\(PasswordAuthentication\s*\).*$/\1 no/' — это $true.

mklement0 30.06.2024 17:31

@mklement0: Я думаю, что вы ошибаетесь, и ОП должен заменить двойные кавычки одинарными. При использовании двойных кавычек люди всегда будут подвергать сомнению знак доллара, и нет никакого вреда в замене двойных кавычек на одинарные.

jdweng 30.06.2024 19:08

@jdweng, да, использование одинарных кавычек, несомненно, предпочтительнее, если следует исключить расширение строки (интерполяцию), как подразумевается в моем предыдущем комментарии. Моя точка зрения заключалась в том, что в данном конкретном случае это не имеет значения, поэтому это не решение. Другими словами: ваш комментарий должен был быть отступлением, четко сформулированным как таковой, а не претендовать на решение.

mklement0 30.06.2024 19:14

@mklement0 Мой точный вывод PowerShell 7.4.3 PS C:\Users\Tirsvad> ssh [email protected] -p 22 sed "s/#\?(UsePAM\s*).*$/\1 no/" /etc /ssh/sshd_config; sed: -e выражение №1, символ 19: незавершенная команда s' command PS C:\Users\Tirsvad> ssh [email protected] -p 22 sed 's/#\?\(UsePAM\s*\).*$/\1 no/' /etc/ssh/sshd_config; sed: -e expression #1, char 19: unterminated s

Tirsvad 01.07.2024 05:37

Вам необходимо защитить обратную косую черту как от локальной, так и от удаленной оболочки. Попробуйте заключить sed -e "s/.../" filename в одинарные кавычки (и разве последняя точка с запятой не является лишней?)

tripleee 01.07.2024 06:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  • Похоже, что ssh не способен передавать произвольные команды с отдельными аргументами, содержащими символы \, в удаленную оболочку, и простое экранирование \ как \\ также не работает.

  • Решение состоит в том, чтобы передать всю командную строку sed как один аргумент ssh:

# From PowerShell:
# Note the use of '...''...''...'
ssh [email protected] -p 22 'sed ''s/#\?\(UsePAM\s*\).*$/\1 no/'' /etc/ssh/sshd_config'

Примечание:

  • Поскольку PowerShell сам интерполирует токены с префиксом $ внутри "..." (расширяемые строки ), лучше использовать '...' ( дословные строки).

    • В отличие от POSIX-совместимых оболочек, таких как Bash, вы можете напрямую вставлять символы ' внутрь '...', экранируя их как '', как показано выше.
  • В тех случаях, когда вам нужна предварительная интерполяция строк с помощью PowerShell, обязательно экранируйте любые сквозные символы $ как `$, т. е. используйте так называемый обратный апостроф, escape-символ PowerShell .

    • Обратите внимание, что \ не имеет особого значения в PowerShell, тогда как он функционирует, например, как escape-символ в POSIX-совместимых оболочках.

    • Кстати: $ chars. за которыми не следует идентификатор (например, $foo) или которые не начинают подвыражение (например, $(1 + 2)), остаются нетронутыми, поэтому нет строгой необходимости экранировать их с помощью `, хотя, вероятно, лучше сделать это по концептуальным причинам; например, "5$/" обрабатывается PowerShell так же, как "5`$/", и возвращает дословно 5$/ (знак $ сохраняется).
      То же самое относится и к POSIX-совместимым оболочкам (за исключением того, что для экранирования $ требуется \$).

  • В вашем вопросе показана попытка вызвать ssh через pwsh -c, то есть через pwsh, интерфейс командной строки PowerShell (Core) 7, в чем нет необходимости: просто вызовите ssh напрямую, как показано выше.

    • Если бы вы звонили напрямую из cmd.exe, вы бы использовали "..." для включения командной строки sed в целом (cmd.exe распознает только двойные кавычки и не интерпретирует $) и только '...' для встроенного скрипта sed.

Вызов вашей команды из Python через subprocess.run():

  • Как уже отмечалось, нет необходимости вызывать через PowerShell CLI.

  • Из Python у вас есть возможность вызывать ssh напрямую, без участия оболочки (будь то PowerShell или cmd.exe).

  • Только в Windows вы все равно можете передать на выполнение всю командную строку, и в этом случае правила кавычек, по сути, такие же, как и в cmd.exe: распознаются только двойные кавычки ("...").

  • Цитирование в рассматриваемом случае становится затруднительным из-за необходимости вложенного кавычек: встроенного "..." кавычек вокруг команды сквозного sed и внутри него '...' кавычек вокруг sed скрипта. Кроме того, символы \ следует сохранить как есть.

  • Самое простое решение — использовать необработанный строковый литерал в тройных кавычках r'''...''', внутри которого ', " и \ могут быть встроены без экранирования.

Поэтому:

import subprocess

# Note: Shell-less invocation (`shell=False` is implied).
#       Passing a whole command line as a single string in a shell-less
#       invocation is supported on Windows only.
subprocess.run(
  r'''ssh [email protected] -v -p 22 "sed 's/#\?\(UsePAM\s*\).*$/\1 no/' /etc/ssh/sshd_config"''', 
  encoding = "utf-8"
)

Спасибо за подробное объяснение. Теперь у меня есть только одна проблема: в моем скрипте Python нужно использовать subprocess.run(#Команда#) и получить тот же результат.

Tirsvad 01.07.2024 14:37

Рад слышать, что это помогло, @Tirsvad. Что касается Python: попробуйте "..." заключить в кавычки всю sed командную строку: subprocss.run('ssh [email protected] -p 22 "sed 's/#\?\(UsePAM\s*\).*$/\1 no/' /etc/ssh/sshd_config"). Если это не поможет, я предлагаю создать новый пост с вопросами, посвященный именно этой проблеме.

mklement0 01.07.2024 16:34

Найдено решение для Python #test.py import subprocess cmd = r"pwsh -Command ssh [email protected] -v -p 22 'sed '\"'s/#\?\(UsePAM\s*\).*$/\1 no/'\"' /etc/ssh/sshd_config'" subprocess.run(cmd.replace('\\\\', '\\'), encoding = "utf-8")

Tirsvad 03.07.2024 06:35

Рад это слышать, @Tirsvad. Действительно, в своем давно удаленном комментарии я использовал обычные строковые литералы Python и не стал экранировать символы \ в них как \\. Использование необработанного строкового литерала действительно предпочтительнее, а его форма в тройных кавычках (r'''...''') позволяет также вставлять ' и " без экранирования, что обеспечивает более простое решение, не требующее ни вызова через pwsh -Command, ни последующей обработки строки — см. обновлять.

mklement0 03.07.2024 22:36

Другие вопросы по теме