Уникніть змінної для використання як вмісту іншого сценарію


20

Це запитання не стосується того, як записати правильно вийшов рядковий літерал. Я не зміг знайти жодного пов'язаного питання, яке стосується того, як уникнути змінних для прямого споживання в сценарії чи іншими програмами.

Моя мета - включити сценарій для генерації інших сценаріїв. Це відбувається тому, що завдання в генерованих сценаріях будуть працювати на будь-якій машині десь від 0 до n разів, а дані, з яких вони генеруються, можуть змінюватися перед їх запуском (знову), тому виконання операцій безпосередньо по мережі не працює.

З огляду на відому змінну, яка може містити спеціальні символи, такі як одинарні лапки, мені потрібно виписати це як повністю уникнутий рядковий літерал, наприклад, змінна, fooщо містить, bar'bazповинна з'являтися в створеному сценарії як:

qux='bar'\''baz'

що було б написано додаванням "qux=$foo_esc"до інших рядків сценарію. Я зробив це за допомогою Perl так:

foo_esc="'`perl -pe 's/('\'')/\\1\\\\\\1\\1/g' <<<"$foo"`'"

але це здається непосильним.

Я не мав успіху в тому, щоб робити це лише з басом. Я перепробував багато варіантів таких:

foo_esc="'${file//\'/\'\\\'\'}'"
foo_esc="'${file//\'/'\\''}'"

але або додаткові косої риски з’являються у висновку (коли я це роблю echo "$foo"), або вони викликають синтаксичну помилку (очікуючи подальшого введення, якщо виконано з оболонки).


aliasта / або setдосить універсально
mikeserv

@mikeserv Вибачте, я не впевнений, що ви маєте на увазі.
Уолф

alias "varname=$varname" varnameабоvar=value set
mikeserv

2
@mikeserv Це недостатньо контексту для мене, щоб зрозуміти, що має робити твоя пропозиція, а також як я би використовував це як загальний метод уникнення будь-якої змінної. Це вирішена проблема, друже.
Вальф

Відповіді:


27

Bash має параметр розширення параметрів саме для цього випадку :

${parameter@Q}Розширення - це рядок, який є значенням параметру, що цитується у форматі, який може бути використаний повторно як вхідний.

Отже, у цьому випадку:

foo_esc="${foo@Q}"

Це підтримується в Bash 4.4 і вище. Існує кілька варіантів і для інших форм розширення, а також для конкретного генерування повних операторів призначення ( @A).


7
Акуратні, але мають лише 4,2, що дає bad substitution.
Уолф

3
Еквівалент оболонки Z дорівнює "${foo:q}".
JdeBP

Дійсно врятуй моє життя! "${foo@Q}"працює!
хао

@JdeBP, що еквівалент оболонки Z не працює. Будь-які інші ідеї для zsh?
Стівен Шоу

1
Я знайшов відповідь: "$ {(@ qq) foo}"
Стівен Шоу

11

Bash надає printfвбудований %qспецифікатор формату, який виконує вимкнення оболонки для вас, навіть у старих (<4.0) версіях Bash:

printf '[%q]\n' "Ne'er do well"
# Prints [Ne\'er\ do\ well]

printf '[%q]\n' 'Sneaky injection $( whoami ) `ls /root`'
# Prints [Sneaky\ injection\ \$\(\ whoami\ \)\ \`ls\ /root\`]

Цей трюк можна також використовувати для повернення масивів даних з функції:

function getData()
{
  printf '%q ' "He'll say hi" 'or `whoami`' 'and then $( byebye )'
}

declare -a DATA="( $( getData ) )"
printf 'DATA: [%q]\n' "${DATA[@]}"
# Prints:
# DATA: [He\'ll\ say\ hi]
# DATA: [or\ \`whoami\`]
# DATA: [and\ then\ \$\(\ byebye\ \)]

Зауважте, що printfвбудований Bash відрізняється від printfутиліти, яка постачається в комплекті з більшістю операційних систем, схожих на Unix. Якщо з якоїсь причини printfкоманда викликає утиліту замість вбудованої, ви завжди можете виконати її builtin printfзамість.


Я не впевнений, як це допомагає, якщо те, що мені потрібно було надрукувати, було б 'Ne'\''er do well'і т. Д., Тобто цитати, що містяться у висновку.
Уолф

1
@Walf Я думаю, ти не розумієш, що дві форми рівноцінні, і обидві ідеально такі ж безпечні, як і одна. Напр. [[ 'Ne'\''er do well' == Ne\'er\ do\ well ]] && echo 'equivalent!'Відлунняequivalent!
Dejay Clayton

Я пропустив це: P, однак я віддаю перевагу цитованій формі, оскільки її легше читати в засобі перегляду / редактора, що виділяє синтаксис.
Вальф

@Walf здається, що ваш підхід є досить небезпечним, враховуючи, що у вашому прикладі Perl передача такого значення, як 'hello'результат, призводить до невірного значення ''\''hello'', яке має непотрібну провідну порожню рядок (перші два одиничні лапки) та невідповідну прострочену єдину цитату.
Dejay Clayton

1
@Walf, для уточнення, $'escape-these-chars'є ANSI-C котирувальною функцією Bash, яка змушує уникати всіх символів у вказаній рядку. Таким чином, легко створити літеральний рядок, який містить новий рядок у назві файлу (наприклад $'first-line\nsecond-line'), використовувати \nв рамках цієї конструкції.
Dejay Clayton

8

Я думаю, я не RTFM. Це можна зробити так:

q_mid=\'\\\'\'
foo_esc="'${foo//\'/$q_mid}'"

Потім echo "$foo_esc"дає очікуване'bar'\''baz'


Як я насправді ним користуюся, це функція:

function esc_var {
    local mid_q=\'\\\'\'
    printf '%s' "'${1//\'/$mid_q}'"
}

...

foo_esc="`esc_var "$foo"`"

Змінивши це для використання printfвбудованого рішення Dejay:

function esc_vars {
    printf '%q' "$@"
}

3
Я б використав рішення @ michael-homer, якби моя версія підтримувала його.
Walf

4

Існує кілька рішень для цитування значення var:

  1. псевдонім
    У більшості оболонок (де доступний псевдонім) (крім csh, tcsh та, ймовірно, інших csh як):

    $ alias qux=bar\'baz
    $ alias qux
    qux='bar'\''baz'

    Так, це працює у багатьох shподібних оболонках, як тире або зола.

  2. set
    також у більшості оболонок (знову ж, не csh):

    $ qux=bar\'baz
    $ set | grep '^qux='
    qux='bar'\''baz'
  3. верстати
    У деяких оболонках (КШ, баш і ЗШ , по крайней мере):

    $ qux=bar\'baz
    $ typeset -p qux
    typeset qux='bar'\''baz'             # this is zsh, quoting style may
                                         # be different for other shells.
  4. експорт
    Перше:

    export qux=bar\'baz

    Потім використовуйте:
    export -p | grep 'qux=' export -p | grep 'qux='
    export -p qux

  5. цитата
    echo "${qux@Q}"
    echo "${(qq)qux}" # від одного до чотирьох q може бути використана.


Підхід псевдоніма розумний і, здається, він визначений POSIX. Для максимальної портативності я думаю, що це шлях. Я вважаю, що пропозиції, пов’язані grepз exportабо setможуть порушувати змінні, що містять вбудовані нові рядки
jw013
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.