Я пишу огромный скрипт-фабрику сценариев, генерирующую множество сценариев обслуживания для моих серверов.
До сих пор я пишу несколько строк, которые нужно записать в одну строку, echo -ne
например,
echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
if(($COUNT != 0))
then
echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
fi
echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
COUNT=$((COUNT+1))
JOBSDONE=$((JOBSDONE+1))
updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"
echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
это генерирует мне (если, например, в моем файле конфигурации 2 сервера)
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
Все остальные блоки кода, которые не нуждаются во встроенном написании кода, который я создаю с помощью heredocs, так как я считаю, что их лучше писать и поддерживать. Например, после верхнего кода у меня есть остальные сгенерированные как
cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
# Print out ExitCode legend
echo " ExitCode 42 - upgrade failed"
echo " ExitCode 43 - Upgrade failed"
echo " ExitCode 44 - Dist-Upgrade failed"
echo " ExitCode 45 - Autoremove failed"
echo ""
echo ""
fi
EOF
Таким образом, окончательный блок кода выглядит
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
# Print out ExitCode legend
echo " ExitCode 42 - upgrade failed"
echo " ExitCode 43 - Upgrade failed"
echo " ExitCode 44 - Dist-Upgrade failed"
echo " ExitCode 45 - Autoremove failed"
echo ""
echo ""
fi
Мой вопрос
Есть ли способ, с помощью которого heredoc ведет себя так же, как и echo -ne
без символа конца строки?
sudo
скрипт, вы делаете это неправильно: вместо этого запустите весь скрипт как root!sudo -u USERNAME
на том , что вместо того, чтобы , увидеть Как запустить команду «» SUDO внутри сценария? ,sudo
без имени пользователя запрашивает пароль, если вы не ввели его с задержкой. Еще хуже, если вы не запустите скрипт в терминале, тогда вы даже не увидите запрос пароля, и он просто не будет работать.sudo -u
Подход не имеет какой - либо из этих проблем.Ответы:
Нет, heredoc всегда заканчивается новой строкой. Но вы все равно можете удалить последний символ новой строки, например, с помощью Perl:
-p
читает строку ввода построчно, выполняет код, указанный в-e
, и печатает (возможно, измененную) строкуисточник
Короткий ответ заключается в том, что heredoc и herestrings просто создаются таким образом, поэтому no-here-doc и herestring всегда будут добавлять завершающий символ новой строки, и нет никакого варианта или встроенного способа его отключения (возможно, будет в будущих выпусках bash?).
Тем не менее, один из способов приблизиться к нему с помощью bash-only способов - это прочитать то, что дает heredoc стандартным
while IFS= read -r
методом, но добавить задержку и вывести последнюю строкуprintf
без завершающего символа новой строки. Вот что можно сделать с bash-only:Здесь вы видите обычный цикл while с
IFS= read -r line
подходом, однако каждая строка сохраняется в переменной и, таким образом, задерживается (поэтому мы пропускаем печать первой строки, сохраняем ее и начинаем печать только после прочтения второй строки). Таким образом, мы можем захватить последнюю строку, и когда на следующей итерацииread
возвращается статус выхода 1, тогда мы печатаем последнюю строку без новой строки черезprintf
. Подробный ? да. Но это работает:Обратите внимание, что
$
символ подсказки выдвигается вперед, так как нет новой строки. В качестве бонуса, это решение является портативным и POSIX-иш, поэтому он должен работать вksh
иdash
а.источник
Я рекомендую вам попробовать другой подход. Вместо того, чтобы соединять ваш сгенерированный скрипт из нескольких эхо-операторов и heredocs. Я предлагаю вам попробовать использовать один heredoc.
Вы можете использовать расширение переменных и подстановку команд внутри heredoc. Как в этом примере:
Я считаю, что это часто приводит к гораздо более читаемым конечным результатам, чем создание выходных данных по частям.
Также похоже, что вы забыли
#!
строку в начале ваших сценариев.#!
Линия является обязательным в любом правильно отформатированных сценариев. Попытка запустить скрипт без#!
строки будет работать только в том случае, если вы вызываете его из оболочки, которая работает с плохо отформатированными скриптами, и даже в этом случае может произойти интерпретация интерпретатором другой оболочки, чем вы предполагали.источник
#!
но мой блок кода - это всего лишь один фрагмент из сценария с 2000 строками;) Сейчас я не вижу, как ваше предложение решает мою проблему генерации одной строки кода в цикле while ...$( ...command...)
внутри heredoc, чтобы вставить вывод этих команд, встроенный в этот момент в heredoc; (3) В Bash есть переменные-массивы, которые вы можете расширить встроенными и использовать подстановки, чтобы добавить вещи в начало / конец, если это необходимо. Вместе они делают предложение Касперда намного более мощным (и ваш сценарий потенциально намного более читабельным).Heredoc всегда заканчиваются символами новой строки, но вы можете просто удалить это. Самый простой способ, который я знаю, с
head
программой:источник
-c
тоже принимает отрицательные значения! Так даже больше, чемpearl
решениеВы можете удалить переводы строк так, как вам нравится, и
tr
, вероятно, будет проще всего использовать конвейерную связь . Это, конечно, удалит все новые строки.Но если оператор if, который вы создаете, не требует этого, арифметическое выражение
(( .. ))
должно работать нормально, даже если оно содержит символы новой строки.Итак, вы могли бы сделать
производства
Тем не менее, создание его в цикле все еще ужасно.
|| 0
Там, конечно , так что нам не нужно частный случай первой или последней строке.Кроме того, у вас есть это
| sudo tee ...
в каждом выходе. Я думаю, что мы могли бы избавиться от этого, открыв перенаправление только один раз (с заменой процесса), и используя это для последующей печати:И, честно говоря, я все еще думаю, что создание имен переменных из переменных во внешнем скрипте (как этот
\$${name}_E
) немного уродливо, и его, вероятно, следует заменить ассоциативным массивом .источник