Лечение обратного слеша через оболочки

9

Как echoи printfлечить слеш zsh, bashи другие снаряды?

Под Zsh я получаю следующее поведение:

$ echo "foo\bar\baz"
foaaz
$ echo "foo\\bar\\baz"
foaaz
$ echo 'foo\bar\baz'
foaaz
$ echo 'foo\\bar\\baz'
foo\bar\baz

В bash все выглядит более согласованным:

bash$ echo "foo\bar\baz"
foo\bar\baz
bash$ echo 'foo\bar\baz'
foo\bar\baz
bash$

Но более конкретно: как я могу передать строку, содержащую обратную косую черту, такую ​​как\\foo\bar\something :

  • echo
  • printf
  • print

и получить точно такую ​​же строку? zshа bash)?

Вот еще один эксперимент с функциями в Zsh:

function foo
{
    echo -E '$1'
}

$ foo \\here\is\some\path
$1

Как я могу это просто напечатать \\here\is\some\path?

Обновление (Примечание: на этот вопрос уже дан ответ в комментарии Стефана)

Я пробовал следующее в zsh 5.0.2:

function foo
{
    printf '$s\n' $1 
}

foo '\\some\path'

Но это печатает $s?

Амелио Васкес-Рейна
источник
3
Использование printf, echoне переносимо в этом отношении.
Иордания
вы выполняете функцию "foo": заменяете 'на "и вызываете ее с помощью: foo '\\ here \ is \ some \ path' (в противном случае вызывающая оболочка получает возможность интерпретировать '\' до того, как они попадут в функцию)
Оливье Дюлак
2
Ваша функция используется, '$s\n'когда она должна была использоваться '%s\n'.
CJM

Ответы:

12

zsh echoведет себя стандартным образом, как bashв режиме UNIX. То есть он расширяется \bдо символа ASCII BS, как того требует спецификация UNIX.

Не используйте echoдля отображения произвольных строк, используйтеprintf :

printf '%s\n' "$1"

print -r -- "$1"также работает, но является ksh/ zshконкретным.

echo -E - "$1"работать с zshи я считаю, что некоторые BSD.

cat << EOF
$1
EOF

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

И, кстати, вам нужно избегать обратной косой черты в командной строке оболочки, так как она особенная для оболочки (каждая оболочка, кроме rc), поэтому:

$ foo '\\foo\bar'

foo \\foo\barпередаст "\foo\bar"строку, в fooкоторую не сможет заново создать потерянный обратный слеш.

Стефан Шазелас
источник
Спасибо Стефан. Как ни странно, конструкция printf '%s\n' "$var"работает для меня в командной строке ( zsh 5.0.2т.е. в самой последней), но не внутри функции (см. Мое обновление в ОП). Почему?
Амелио Васкес-Рейна
1
Это printf '%s\n'не printf '$s\n'ты хочешь. Обратите внимание, что вам нужно заключать переменные в другие оболочки, отличные от zsh( "$1", не $1), и стандартный синтаксис определения функции foo() { ...; }, хотя любая оболочка, но bashпозволяет foo() any-command, и function foo { .... }является kshсинтаксисом.
Стефан Шазелас
@ Маркус, это ответ на другой вопрос.
Стефан
1

новый ответ: прочитайте -r var

-r  raw input - disables interpretion of backslash escapes and line-continuation in the read data

и отобразить:

printf "%s" "$var"
echo "$var"

должно сработать.

Итак, для вашей функции foo:

function foo
{
    read -r var
    echo -E "var is : ${var}"
}

$ foo 
\\here\is\some\path
var is : \\here\is\some\path

старый ответ ниже (не отвечает, но может быть полезным ^^)

просто замените каждый \на, \\чтобы сказать оболочке «что это буквально все, что \я хочу». в противном случае (например, в zsh, в вашем примере) вполне может быть, что \bозначает «1 возврат» или что-то еще.

Вы можете, например, использовать sed:

sed -e 's,\\,\\\\,g' < the_original > the_escaped_backslaches_version

(посмотрите, как вам также нужно убежать "\" там, чтобы сказать sed то же самое: "это буквально" \ "Я хочу) (и обратите внимание, что я окружаю его символом '', а не" ", чтобы избежать интерпретации оболочки большинство тоже)

Оливье Дюлак
источник
Спасибо, но, как я уже упоминал в заголовке: я хочу избежать обратной косой черты.
Амелио Васкес-Рейна
Ой, я отредактирую ^^
Оливье Дюлак
Спасибо! Но, read -r varкажется, ждать ввода от STDIN. Что если я передам это в качестве аргумента? (например, foo \\here\is\some\path)
Амелио Васкес-Рейна
оболочка интерпретирует обратную косую черту. Вот почему вам, вероятно, следует переместить аргумент, передаваемый в чтение, см. Мой пример "foo".
Оливье Дюлак
1
iow: вы хотите "нестандартную" обработку строк оболочкой: вы могли бы легче (и более активно) сделать вашу программу совместимой с тем, что вы хотите, вместо того, чтобы пытаться заставить оболочку вызывать эту программу для ведите себя так, как вы хотите. Итак: передайте аргументы (те, которые содержат «\», которые вы не хотите экранировать) после запуска программы, через «read -r», а не в вызывающей командной строке оболочки.
Оливье Дюлак
1

Вообще говоря, вы не можете, потому что обратная косая черта является escape-символом (и поэтому должна быть экранирована, когда требуется ее буквальное значение). BASH предоставляет одинарные кавычки для этой цели, однако вы не можете использовать экранирование одинарных кавычек в одинарных кавычках.

Что касается echoнесоответствия, то это встроенная функция может вести себя по-разному в различных оболочках (в некоторой степени). Например, встроенная функция BASH имеет -eопцию, которая указывает ей интерпретировать последовательности обратной косой черты - с ее помощью вы получите поведение, которое вы видели в оболочке Z.

peterph
источник