как предотвратить экранирование специальных символов в цикле в качестве аргумента для другой команды?

rm -r удаляет каталог и все его содержимое; rmdirудалит каталог, только если он пуст. Мне нравится использовать следующее для удаления каталога и всего его содержимого:

rm -rf <directory_to_be_removed>
3
08.09.2019, 15:47
2 ответа

С помощью /opt/report -filesystem "$line" -detailhost.fqdn.com:/ 'host.fqdn.com [/]'передается дословно как один аргумент команды, и вывод set -xговорит вам именно об этом, показывая значение в одинарных кавычках, которые являются дословными кавычками в снаряды.

В

/opt/report -filesystem host.fqdn.com:/ 'host.fqdn.com [/]'

Вы передаете два аргумента команде:host.fqdn.com:/и host.fqdn.com [/]. Это связано с тем, что символ пробела и символы одинарной кавычки являются особыми в синтаксисе оболочки.

Для оболочки, как показано выше, '...'— это дословные кавычки, которые служат для передачи текста буквально без специального обращения с каким-либо символом внутри, и SPC (, когда он сам не цитируется )в синтаксис оболочки используется для разделения аргументов (или, в более общем смысле, токенов в синтаксисе оболочки )

.

Если вы хотите передать host.fqdn.com:/ 'host.fqdn.com [/]'буквально как один аргумент, как показано в выводе set -x, вам понадобится что-то вроде 'host.fqdn.com:/ '\''host.fqdn.com [/]'\''', хотя использование других типов кавычек, таких как "host.fqdn.com:/ 'host.fqdn.com [/]'", также будет работать.

$ printf '<%s>\n' 'host.fqdn.com:/ '\''host.fqdn.com [/]'\'''
<host.fqdn.com:/ 'host.fqdn.com [/]'>
$ printf '<%s>\n' "host.fqdn.com:/ 'host.fqdn.com [/]'"
<host.fqdn.com:/ 'host.fqdn.com [/]'>

Если вам действительно нужно, чтобы host.fqdn.com:/ 'host.fqdn.com [/]'интерпретировался как код оболочки, а не как один литеральный аргумент для передачи команде, вам нужно будет вызвать интерпретатор оболочки для содержимого $line, как с вашим конвейером. на bash(, хотя ваше использование двойных кавычек было неправильным )илиeval:

#!/bin/bash -
set -x
while IFS= read -r line; do
  eval "/opt/report -filesystem $line -detail"
done < objects.lst

Однако это означает, что если строка содержит, например, ;reboot;или $(reboot), это вызовет команду reboot.

Если вы хотите выполнить только токенизацию оболочки и удаление кавычек без других побочных эффектов, таких как выполнение этих команд rebootвыше, вы можете вместо этого использовать zsh, который имеет операторы для этого:

#!/bin/zsh -
set -x
while IFS= read -r line; do
  /opt/report -filesystem "${(Q@)${(z)line}}" -detail
done < objects.lst

Где zвызывает токенизацию как код zsh, а Qудаляет один слой кавычек. Например, в строке вида:

foo 'bar baz' $(echo x y)

Будет передано 3 аргумента :foo, bar bazи $(echo x y).

4
27.01.2020, 21:15

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

Если все эти строки следуют этому формату (и нет строк со строками в кавычках ), вы можете сделать что-то подобное в Bash:

#/bin/bash
while IFS=" " read -r a b; do
    b=${b%\'};
    b=${b#\'};
    /opt/report -filesystem "$a" "$b" -detail
done < objects.lst

readразбивает строку на две части в первом пробеле и сохраняет части в aи b. Затем b=${b%\'}; b=${b#\'};удалите одинарные кавычки, а затем обе строки передаются как отдельные аргументы в /opt/report.

1
27.01.2020, 21:15

Теги

Похожие вопросы