Робота з декількома рівнями цитування (насправді, декількома рівнями розбору / інтерпретації) може ускладнитися. Це допомагає пам’ятати про кілька речей:
- Кожен "рівень котирування" потенційно може містити різну мову.
- Правила цитування залежать від мови.
- У роботі з більш ніж одним або двома вкладеними рівнями, як правило, найпростіше працювати "знизу, вгору" (тобто від найглибшого до зовнішнього).
Рівні цитування
Давайте розглянемо ваші приклади команд.
pgrep -fl java | grep -i datanode | awk '{print $1}'
Ваша перша команда прикладу (вище) використовує чотири мови: оболонку, регулярний вираз у pgrep , регулярний вираз у grep (що може відрізнятися від мови регулярного виразів у pgrep ) та awk . Задіяні два рівні інтерпретації: оболонка та один рівень після оболонки для кожної із залучених команд. Є лише один явний рівень котирування (цитування оболонки в awk ).
ssh host …
Далі ви додали рівень ssh зверху. Це фактично інший рівень оболонки: ssh не інтерпретує саму команду, передає її оболонці на віддалений кінець (через (наприклад) sh -c …
), і ця оболонка інтерпретує рядок.
ssh host "sudo su user -c …"
Потім ви запитали про додавання іншого рівня оболонки в середині за допомогою su (через sudo , який не інтерпретує його аргументи команд, тому ми можемо ігнорувати його). На даний момент у вас три рівні гніздування ( awk → shell, оболонка → shell ( ssh ), оболонка → оболонка ( su user -c ), тому я раджу використовувати підхід «знизу, вгору». ваші снаряди сумісні з Борном (наприклад, ш , зола , тире , кш , баш , зш тощо). Деякі інші види оболонки ( риба , рстощо) може вимагати різного синтаксису, але метод все-таки застосовується.
Внизу, вгору
- Сформулюйте рядок, який ви хочете представляти на найглибшому рівні.
- Виберіть механізм цитування з репертуару цитування наступної найвищої мови.
- Цитуйте потрібний рядок відповідно до обраного механізму цитування.
- Часто існує багато варіацій, як застосувати який механізм котирування. Робити це вручну, як правило, є питанням практики та досвіду. Роблячи це програмно, зазвичай, найкраще вибрати найпростіший, щоб правильно вийти (як правило, "найбільш буквальне" (найменше втечі)).
- За бажанням використовуйте отриманий рядок, що цитується, з додатковим кодом.
- Якщо ви ще не досягли бажаного рівня цитування / інтерпретації, візьміть отриманий рядок (цитуючи доданий код) та використовуйте його як початковий рядок на кроці 2.
Цитуючи семантику Вари
Тут слід пам’ятати, що кожна мова (рівень котирування) може дати трохи різну семантику (або навіть різко різну семантику) одному і тому ж символу цитування.
Більшість мов мають "буквальний" механізм цитування, але вони різняться в тому, наскільки вони буквальні. Одинарна цитата оболонок Борна насправді буквальна (а це означає, що ви не можете використовувати її для цитування самого одного символу цитати). Інші мови (Perl, Ruby) менш буквальні в тому , що вони інтерпретують деякі зворотні косі риси послідовностей всередині окремі цитовані регіонів , НЕ в буквальному сенсі ( в приватність, \\
і \'
результат \
і '
, але і інші послідовності з зворотними косою рисою, на самому ділі дослівні).
Вам потрібно буде прочитати документацію для кожної з мов, щоб зрозуміти її правила котирування та загальний синтаксис.
Ваш приклад
Найпотаємніший рівень вашого прикладу - це програма awk .
{print $1}
Ви збираєтеся вставити це в командний рядок оболонки:
pgrep -fl java | grep -i datanode | awk …
Ми повинні захистити (як мінімум) простору і $
в AWK програмі. Очевидним вибором є використання однієї цитати в оболонці навколо всієї програми.
Однак є й інші варіанти:
{print\ \$1}
безпосередньо вирватися з космосу і $
{print' $'1}
єдина цитата лише простір і $
"{print \$1}"
подвійну цитату цілого і втекти від $
{print" $"1}
подвійний цитата лише пробіл, і $
це може бути трохи згинати правила (немальований $
в кінці рядка з подвійним цитуванням є буквальним), але, здається, він працює в більшості оболонок.
Якщо програма використовувала кому між відкритими і закритими фігурними дужками, нам також потрібно було б процитувати або вийти з коми або фігурних дужок, щоб уникнути "розширення дужки" в деяких оболонках.
Ми вибираємо '{print $1}'
і вставляємо його в решту оболонки «код»:
pgrep -fl java | grep -i datanode | awk '{print $1}'
Далі ви хотіли запустити це через su і sudo .
sudo su user -c …
su user -c …
так само some-shell -c …
(за винятком запуску під деяким іншим UID), тому su просто додає ще один рівень оболонки. sudo не інтерпретує свої аргументи, тому не додає рівнів цитування.
Нам потрібен інший рівень оболонки для нашого командного рядка. Ми можемо знову вибрати одне котирування, але ми мусимо надати особливу обробку існуючим єдиним котируванням. Звичайний спосіб виглядає так:
'pgrep -fl java | grep -i datanode | awk '\''{print $1}'\'
Тут є чотири рядки, які оболонка буде інтерпретувати та об'єднувати: перший сингл ( pgrep … awk
), що цитується, (єдиний цитат , що уникнув, програма awk з одною цитатою, інша цитата, що уникнула).
Звичайно, існує безліч альтернатив:
pgrep\ -fl\ java\ \|\ grep\ -i\ datanode\ \|\ awk\ \'{print\ \$1}
уникнути всього важливого
pgrep\ -fl\ java\|grep\ -i\ datanode\|awk\ \'{print\$1}
те саме, але без зайвих пробілів (навіть у програмі awk !)
"pgrep -fl java | grep -i datanode | awk '{print \$1}'"
подвійно цитуйте всю річ, уникайте $
'pgrep -fl java | grep -i datanode | awk '"'"'{print \$1}'"'"
Ваша варіація; трохи довше, ніж звичайний спосіб, завдяки використанню подвійних лапок (два символи) замість втечі (один символ)
Використання різних котирувань на першому рівні дозволяє отримати інші варіанти на цьому рівні:
'pgrep -fl java | grep -i datanode | awk "{print \$1}"'
'pgrep -fl java | grep -i datanode | awk {print\ \$1}'
Вбудовуючи першу варіацію в командний рядок sudo / * su *, надайте це:
sudo su user -c 'pgrep -fl java | grep -i datanode | awk '\''{print $1}'\'
Ви можете використовувати ту саму рядок у будь-якому іншому контексті одного оболонки (наприклад ssh host …
).
Далі ви додали рівень ssh зверху. Це фактично інший рівень оболонки: ssh не інтерпретує команду, а передає її оболонці на віддалений кінець (через (наприклад) sh -c …
), і ця оболонка інтерпретує рядок.
ssh host …
Процес той самий: візьміть рядок, виберіть метод цитування, використовуйте його, вставте його.
Використання одинарних лапок:
'sudo su user -c '\''pgrep -fl java | grep -i datanode | awk '\'\\\'\''{print $1}'\'\\\'
Зараз є одинадцять рядків, які інтерпретуються та об'єднуються:, 'sudo su user -c '
уникнув єдиний цитат, 'pgrep … awk '
уникнув єдину цитату, уникнув зворотній косий ривок, дві уникнуті одиночні цитати, єдину програму awk , єдину цитату, що уникнув, та остаточну цитату, що уникнув .
Заключна форма виглядає приблизно так:
ssh host 'sudo su user -c '\''pgrep -fl java | grep -i datanode | awk '\'\\\'\''{print $1}'\'\\\'
Це трохи важко вводити вручну, але буквальний характер єдиного котирування оболонки дозволяє легко автоматизувати невеликі зміни:
#!/bin/sh
sq() { # single quote for Bourne shell evaluation
# Change ' to '\'' and wrap in single quotes.
# If original starts/ends with a single quote, creates useless
# (but harmless) '' at beginning/end of result.
printf '%s\n' "$*" | sed -e "s/'/'\\\\''/g" -e 1s/^/\'/ -e \$s/\$/\'/
}
# Some shells (ksh, bash, zsh) can do something similar with %q, but
# the result may not be compatible with other shells (ksh uses $'...',
# but dash does not recognize it).
#
# sq() { printf %q "$*"; }
ap='{print $1}'
s1="pgrep -fl java | grep -i datanode | awk $(sq "$ap")"
s2="sudo su user -c $(sq "$s1")"
ssh host "$(sq "$s2")"