Имеет ли Tcl или Expect возможность заключать аргументы в кавычки таким образом, чтобы их можно было анализировать оболочкой?

Рассмотрим следующую короткую программу Expect:

#!/usr/bin/expect

puts $::argc
puts $::argv

Если я вызову его следующим образом, он правильно определит, что имеется четыре элемента, но естественное tcl-представление массива argv не может быть напрямую передано в оболочку.

./Test.exp x y z "a b c"
4
x y z {a b c}

Можно ли заставить TCL выводить аргументы в удобном для оболочки виде, чтобы я мог передать их в другую программу через send?

Для ясности: я знаю, что могу напрямую передать аргументы spawn или exec.

Однако я хотел бы знать, возможно ли send передать аргументы порожденной оболочки (например, bash), что требует правильного цитирования оболочки.

Это полезно для отправки последовательности команд в bash с использованием аргументов, переданных в сценарий ожидания, и для возможности протоколировать весь псевдоинтерактивный сеанс.

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

Charles Duffy 09.08.2024 21:44

Да, я это понимаю, как я указал в вопросе.

merlin2011 09.08.2024 21:45

Не уверен, но этот вопрос может быть тем, что вам нужно.

Barmar 09.08.2024 22:03

Нет, я уже видел это. Мне известно о решении exec, и этот вопрос конкретно касается цитирования оболочки.

merlin2011 09.08.2024 22:58
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Ленивый способ — использовать сам bash для экранирования. Таким образом, вам не придется учитывать каждый специальный символ и крайний случай, который может возникнуть; оболочка уже знает о них и может обработать их за вас.

#!/usr/bin/env tclsh

# Take a list and return a single string with the elements of that list
# escaped in a way that bash can split back up into individual elements
proc quote_args {raw} {
    string map {"\n" " "} [exec bash -c {printf "%q\n" "$@"} bash {*}$raw]
}

# Demonstrate usage by calling a shell with a single argument including the
# escaped arguments
set quoted_argv [quote_args $argv]
puts "Escaped: $quoted_argv"
puts [exec bash -c "printf \">%s<\\n\" $quoted_argv"]

Пример использования:

$ ./args.tcl x y z "a b c"
Escaped: x y z a\ b\ c
>x<
>y<
>z<
>a b c<
$ ./args.tcl x y z $'a b\nc' # Works with embedded newlines
Escaped: x y z $'a b\nc'
>x<
>y<
>z<
>a b
c<
$ ./args.tcl 'a b$c' # And things that look like shell parameters that shouldn't be substituted
Escaped: a\ b\$c
>a b$c<

Насколько я могу судить, это самое надежное решение. Сегодня я узнал о printf '%q'!

merlin2011 10.08.2024 00:06

Если пойти другим путем, в tcllib есть пакет для разбиения строки кавычками оболочки (но только sh, никаких расширений вроде bash анси-кавычек).

Shawn 10.08.2024 06:02

Строку для вывода необходимо построить:

#!/usr/bin/expect
set output {}
foreach arg $argv {
    set escaped_arg [string map {"\\" "\\\\" "\"" "\\\""} $arg]
    if {[regexp { } $escaped_arg] || [regexp {'} $escaped_arg]} {
        lappend output "\"$escaped_arg\""
    } else {
        lappend output $escaped_arg
    }
}
puts $argc
puts [join $output " "]

Также необходимо экранировать символы табуляции, $ и, возможно, другие символы.

Shawn 10.08.2024 00:00

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

#!/usr/bin/expect

puts $::argc
puts $::argv

# tcl 8.5 does not have lmap, so this implementation is placed here.
proc map {fun list} {
  set res {}
  foreach element $list {lappend res [$fun $element]}
  set res
}

# Turn an individual argument into a string that the shell likes.
proc transformArg {arg} {
  if {[string first "'" $arg] == -1} {
    return "'$arg'"
  }
  proc wrapInSingleQuote {x} {return "'$x'"}
  return [join [map wrapInSingleQuote [split $arg {'}] ] {"'"}]
}

foreach arg $::argv {
  lappend changedArg [transformArg $arg]
}
puts [join "$changedArg" " "]

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