На FreeBSD 11 для ARMv6 (Raspberry Pi) мне не удалось заставить директиву crontab @reboot
работать для пользователя root , а метод «добавить скрипты в файл /etc/rc.local
» был заменен механизмом, который автоматически запускает скрипты, расположенные в /usr/local/etc/rc.d/
.
Другими словами, чтобы запустить сценарий при загрузке FreeBSD 11 (или 10?) И, вероятно, новее, поместите исполняемый сценарий оболочки с расширением .sh в эту папку, чтобы он запускался при загрузке. :
/usr/local/etc/rc.d/
Возможно, вам потребуется создать папку rc.d
, если она не существует.
См. http://www.defcon1.org/html/rc-local.html для получения подробной информации.
Это изменит IP-адрес, связанный с хостом c
, на 1.2.3.4
:
$ sed 's/^ip/\nip/' file | perl -00pe 'if(/\nhost=c\n/){s/ip=\S+/ip=1.2.3.4/} s/\n\n/\n/'
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=1.2.3.4
mask=255.0.0.0
host=c
ip=x.x.x.x
blahblah
mask=255.0.0.0
host=d
sed 's/^ip/\nip/' file
:добавьте дополнительную новую строку(\n
)к каждой строке, начинающейся с ip
. Я думаю, что это может работать не со всеми реализациями sed
, поэтому, если ваша не поддерживает это, замените команду sed
на perl -pe 's/^ip/\nip/'
. Это нужно для того, чтобы использовать «режим абзаца» Perl (, показанный ниже ).
perl -00pe
:-00
заставляет Perl работать в «режиме абзаца», где «строка» определяется двумя последовательными символами новой строки. Это позволяет нам рассматривать каждый блок хоста как одну «линию». -pe
означает «печатать каждую строку после применения к ней сценария, заданного -e
».
if(/\nhost=c\n/){s/ip=\S+/ip=1.2.3.4/}
:если эта «строка» (раздел )соответствует новой строке, за которой следует строка host=c
, а затем еще одна новая строка, то замените ip=
и 1 или более не -пробельных символов(\S+
)после нее с ip=1.2.3.4
.
s/\n\n/\n/
замените каждую пару новых строк одной новой строкой, чтобы вернуть исходный формат файла. Если вы хотите изменить файл на месте, вы можете использовать:
tmp=$(mktemp); sed 's/^ip/\nip/' file > $tmp;
perl -00pe 'if(/\nhost=c\n/){s/ip=\S+/ip=1.2.3.4/} s/\n\n/\n/' $tmp > file
Я знаю, ты ждешь чего-то очень быстрого,и просто, как однострочная команда sed -или умный код awk, но если вам все равно...
#!/bin/bash
#Note: Adjusted to run with a posix shell (tested in dash)
filename='file'
newip='127.0.0.1'
hostchar='d'
tac "$filename" | while IFS= read -r line ; do
case $line in
host=${hostchar})
flag=on
;;
host=*)
flag=off
;;
esac
if [ "$flag" = "on" ]; then
case $line in
ip=*)
echo ip=$newip
continue
;;
#you can replace more variables at once by adding it here
#in the same standard.
#for ex: mask=*) echo mask=$newmask; continue ;; etc...
esac
fi
echo $line
done | tac
Результаты:
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=x.x.x.c
mask=255.0.0.0
host=c
ip=127.0.0.1
blahblah
mask=255.0.0.0
host=d
Это становится намного проще, если вы просматриваете файл в обратном порядке. К счастью, вы можете легко сделать это с помощью tac
(, который оказывается cat
наоборот ). Затем мы можем использовать относительно простой скрипт awk
для поиска вашего host
и изменить только егоip
:
$ tac input | awk -v OFS="=" -v myip="changed_address" -v myhost="d" -F"=" '$1 == "host" { if( $2 == myhost ) { sw = "on" } else { sw="off" } } sw == "on" && $1 == "ip" { $2=myip } { print $0 }' | tac
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=x.x.x.c
mask=255.0.0.0
host=c
ip=changed_address
blahblah
mask=255.0.0.0
host=d
Я подробно объясню, как работает awk
:
Во-первых, мы объявляем несколько переменных :по одной для host
и новое значение для ip
:
-v myip="changed_address" -v myhost="d"
Далее объявляем разделитель полей для ввода и вывода:
-v OFS="=" -F"="
Теперь собственно сам awk
скрипт:
$1 == "host" { // If we see the "host" line..
if( $2 == myhost ) { // And it matches the one we're looking for..
sw = "on" // Set a flag to swap the next IP
} else {
sw="off" // Otherwise, unset the flag
}
}
sw == "on" && $1 == "ip" { // If the flag is set and this is an IP line..
$2=myip // Swap in the new IP
}
{
print $0 // Finally, print out the processed line
}
Как только все это будет сделано, мы просто используем tac
еще раз, чтобы повторно -перевернуть его, снова сделав его вперед.
Другой вариант — отправить несколько команд наed
:
h=c
ed -s file <<< $'/^host='"${h}"$'$\n?^ip=\nc\nip=new.ip.here\n.\nw\nq' > /dev/null
Основная идея состоит в том, чтобы отредактировать файл и конвейер в разделенном новой строке -списке команд (в двух строках кавычек ANSI C $'... '
), которые ищут данный хост (в переменной $h
), затем выполните поиск строки, начинающейся с ip=
, затем измените эту строку на что-то новое, затем сохраните и закройте ed
. Разделенные символами новой строки (\n
), команды:
/^host=
...$h
$
--начать поиск(/
)строки host=
в начале строки (^
), затем следует содержимое $h
и конец строки($
). Ослабьте требования к концу строки -из -, если ваш хост не полностью совпадает.
?^ip=
--Теперь, когда мы находимся на совпадающей строке, найдите текст ip=
в начале строки в обратном направлении.
c
--изменить эту строку
вставить текстip=new.ip.here
.
--конец текста вставки
w
--записать файл на диск
q
--уволился
Вызов ed с -s
отключает счетчик байтов -, который выдается при открытии и сохранении файла. Перенаправление всей команды на /dev/null
отключает вывод по умолчанию, когда ed
находит строки host=
и ip=
, которые мы ищем.
$ awk -v host=c -v newip=zzz.zzz.zzz.zzz '$0 ~ "^host=" host "$" { print; getline; $0 = sprintf("ip=%s\s", newip) }; 1' file
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=x.x.x.c
mask=255.0.0.0
host=c
ip=zzz.zzz.zzz.zzzs
blahblah
mask=255.0.0.0
host=d
Предполагается, что вы хотите изменить IP-адрес некоторого именованного хоста и что строка IP-адреса всегда находится после строки host=
для этого хоста.
Программа awk
берет имя хоста и новый IP-адрес в командной строке, устанавливая две переменные awk
host
и newip
. Затем код находит строку host=
, соответствующую заданному имени хоста, считывает и отбрасывает следующую строку (, строку ip=
, строку )и создает новую строку ip=
с новым IP-адресом. Данные (изменены или нет )выводятся завершающим 1
в программе.
Относительно короткое решение с использованием утверждений отрицательного просмотра вперед в регулярном выражении perl:
perl -p0e 's/(ip=)[^\n]*((?:(?!ip=).)*?host=c)/\1new_ip_for_host_c\2/gs' hosts.txt
Сначала используется цикл печати -с использованием опции -p
. Это перебирает строки файла, предоставленного в качестве аргумента для perl
, и печатает их. Если строка изменена, печатается измененный вариант,как с sed
.
Содержимое файла на самом деле не обрабатывается как отдельные строки, опция -p
просто служит для того, чтобы заставить perl
сразу читать файл и использовать содержимое в качестве строки по умолчанию для сопоставления без использования переменной. Это достигается с помощью параметра -0
, который заставляет perl
обрабатывать многострочный ввод как одну строку, заменяя символы новой строки нулевыми байтами.
В шаблоне сохраняются части, за исключением изменяемого значения.
Значение распознается как любое до следующей новой строки, которая, как я предполагаю, понимается как следующий нулевой -байт в этой ситуации. Кто-то, кто знает это, возможно, может объяснить.
Затем, используя утверждение отрицательного просмотра вперед, сопоставляются все символы, которым не предшествует часть ip=
, пока не встретится часть host=d
. Это необходимо, иначе perl предпочел бы наиболее левое -совпадение кратчайшему и сопоставлялся бы с самой первой ip=
до требуемой host=c
части.
Символы, которым не предшествует ip=
, сопоставляются не -жадным образом, в противном случае, опять же, совпадение будет охватывать все, начиная с первого ip=
до host=c
, поскольку по умолчанию предпочтение отдается самому длинному совпадению.. Другими словами, это гарантирует, что текст сопоставляется в разделах, заканчивающихся host=c
и начинающихся сегментом ip=
, ближайшим к host=c
, а не самым дальним.
Символ, ограниченный отрицательным опережающим выражением внутри конструкции (?:)
. Он обозначает не захватывающую группу -, что означает, что она не будет учитываться в общем количестве обратных ссылок в строке подстановки. Группировка используется для того, чтобы знак *
мог правильно количественно оценить всю комбинацию символов с отрицательным опережением -как один атом. В примере обратные ссылки варьируются от \1
-\2
, в то время как без захватывающей группы, не являющейся -, они будут \1
-\3
, где \3
обозначает вложенную группу.
Обратные ссылки \1
и \2
в строке подстановки — это совпадающие части раздела, которые точно содержат IP-адрес хоста, найденного в совпавшем разделе.
Таким образом, IP-адрес будет заменен на new_ip_for_host_c
.
Я не уверен, что формат данных был выбран ОП, просто выкладывая это в общем :лучше хранить такие простые данные таким образом, чтобы записи разделялись символами новой строки, т.е. не было многострочных записей. Обратитесь к формату /etc/passwd. Большинство стандартных фильтров Unix ориентированы на строку -, и манипулирование данными становится намного проще, если вы следуете "da Unix wae". Если ваши данные являются более сложными (, вложенными элементами данных и т. д. ), вам лучше использовать такой формат, как JSON, и манипулировать им с помощью соответствующего синтаксического анализатора.