Проблема решена.
На виртуальной машине возникли проблемы с сетью, препятствующие успешному выполнению ntpd. Он имеет два интерфейса eth
, а интерфейс со шлюзом проходит через маршрутизатор, которым мы не управляем напрямую. Хотя мои тесты этого не показали, я предполагаю, что некоторые кадры UDP были заблокированы. Мы настроили другую виртуальную машину с другой сетевой конфигурацией, и ntpq
дал лучшие результаты.
В конечном итоге мы изменили конфигурацию ntp
, чтобы хост транслировал время локально, а все виртуальные машины синхронизировались с ним. Имеет больше смысла и минимизирует нагрузку на общедоступные ntp
серверы.
ntpd
устанавливает часы мгновенно через несколько минут Одна вещь, которая, вероятно, ввела меня в заблуждение во время тестов, - это то, что ntpd синхронизируется не сразу. Я думал, что он сразу обнаружит разрыв, а затем изменит тактовую частоту, чтобы часы постепенно присоединялись к исходным часам.Фактически, мы заметили, что (если ntpd
не перезапущен) часы не меняются в течение нескольких минут, а затем внезапно устанавливаются, как кажется, мгновенно. Между тем, крайние правые столбцы в выходных данных ntpq
показывают, что синхронизация продолжается.
Такое поведение ntpd
, вероятно, объясняет, почему я думал, что ntpd
не работает, даже если и работает. Я просто не ждал достаточно долго и не понял вывода ntpq
.
Все, что заключено в одинарные кавычки, будет передано точно так, как вы его напечатали. Таким образом, command '$i'
передаст команде строку, состоящую из двух символов $
и i
.
Вы должны использовать двойные кавычки, чтобы вместо этого использовать значение переменной
for i in `cat $1`
do
command "$i"
done
Или, поскольку ваш код ожидает одно слово в строке в вашем файле, замените весь цикл этой единственной строкой:
xargs -n1 -r command <"$1"
Вы можете использовать команду без кавычек:
for i in `cat $1`
do
command $i
done
С одинарной кавычкой'$i'
:вы получаете буквально $i
.
С двойной кавычкой"$i"
:вы получаете значения в $i
, но в виде одной строки (, что обычно является желаемым поведением ).
Без кавычек$i
:это будет расширяться как значение в $i
, но затем аргументы будут разделены. Итак, если у вас есть место, например. -a -b
, с двойными кавычками у вас есть аргумент -a -b
, который обычно не ожидается, но в последнем случае у вас будут -a
и -b
как два разных аргумента.
Я должен сообщить вам, что отказ от использования кавычек часто является проблемой безопасности, поэтому вы должны делать это, только если вы действительно знаете, что ввод не является вредоносным.
Это может выполняться по запросу:
while read i
do
command "'$i'"
done < "$1"
Если вы хотите вызвать command
для каждой строки файла (, чей путь хранится в $1
), с содержимым строки, переданным дословно как один единственный аргумент в command
, тогда вы должны использовать:
С помощью GNUxargs
:
xargs -d '\n' -n 1 -r -a "$1" command
С оболочками POSIX:
while IFS= read -r line <&3; do
command "$line" 3<&-
done 3< "$1"
Ваш
for i in `cat $1`; do
command '$i'
done
Помимо очевидной проблемы, заключающейся в том, что он передает буквальную строку $i
в command
, есть несколько других проблем:
$1
, что означает, что он подлежит разделению + подстановке, что означает, что он не будет работать должным образом для путей к файлам, которые содержат пробелы, табуляции, символы новой строки или подстановочные знаки --
, чтобы обозначить конец параметров как cat
, что означает, что это не будет работать должным образом для путей к файлам, начинающихся с -
. Даже с cat -- "$1"
это не сработает для файла с именем -
. cat < "$1"
было бы лучше. Обратите внимание, что если ваш command
также принимает опции, вам также может понадобиться использовать --
там(xargs... command --
или command -- "$line"
)`cat $1`
снова вызывает оператор split+glob. Таким образом, это не цикл по строкам файла, а по списку файлов, которые соответствуют каждому из шаблонов глобусов, которые являются результатом разделения содержимого файла.