#!/usr/bin/perl -i use strict; # The %re hash holds the regexp searches and replacement strings. my %re = (); my $tfile = shift; open(TEMPLATE, "<", $tfile) || die "couldn't open $tfile for read: $!\n"; while() { chomp; my ($search,$replace) = split; $re{qr/$search/} = $replace; }; close(TEMPLATE); while (<>) { foreach my $s (keys %re) { s/$s/$re{$s}/g; }; print; }
Это читает файл
template
и создает ассоциативный массив (, также известный как "хеш" ), называемый%re
поиском и заменой регулярных выражений.Затем он перебирает все оставшиеся имена файлов в командной строке (, например.
input
)и выполняет все эти операции поиска и замены для каждой строки ввода. Он используетqr//
для предварительной -компиляции регулярных выражений -это всего лишь тривиальная оптимизация, если вtemplate
не так много строк, но может привести к очень значительному ускорению, если строк много.
-i
в строке#!/usr/bin/perl -i
заставляет Perl вносить изменения в -поместить во входные файлы, а не просто выводить изменения на стандартный вывод. Измените это, например, на-i.bak
, если вы хотите, чтобы сохранялась резервная копия файлов до того, как они были изменены.Сохранить как, например,
cryptic0.pl
, сделать его исполняемым с помощьюchmod +x cryptic0.pl
и запустить так:$./cryptic0.pl template input
Сценарий не будет выводить данные на терминал. Вместо этого он отредактирует входной файл (с ).
Например, ваш файл
input
будет изменен на:$ cat input gene_id "AT1G01030"; gene_id "AT1G01030"; gene_id "AT1G01010"; gene_id "AT1G01035";
Кстати, этот сценарий изменит все совпадения во всех строках на соответствующую строку замены. Если вы уверены, что в любой данной строке может быть только одно совпадение, вы можете ускорить его, изменив эту строку:
s/$s/$re{$s}/g;
к этому:
s/$s/$re{$s}/ && last;
Это приводит к тому, что сценарий переходит из цикла foreach к оператору
Кстати, см. Почему использование цикла оболочки для обработки текста считается плохой практикой? почему не рекомендуется выполнять обработку текста с помощью циклов sh. Используйте
awk
илиperl
илиsed
или что-то другое вместоsh
илиbash
.
Интерфейс, используемый для каждого типа ссылки, отличается. Скажем, интерфейс Ethernet может быть eth0 , а интерфейс WLAN может быть wlan0 . Зная имена, вы могли бы найти, что является активным и действовать соответственно.
Чтобы вывести список всех интерфейсов и показать их статус, используйте команду ip link show
. Эта команда работает в современных версиях Linux, а также в остальных утилитах и оболочке Bash. Я предполагаю, что вы можете адаптировать его к любой ОС. (В Windows я предлагаю использовать cygwin и awk или Python для анализа вывода ipconfig или netsh , или PowerShell Get -Модуль NetAdapter).
Пример вывода:
user@host$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:50:56:9b:90:7d brd ff:ff:ff:ff:ff:ff
Затем вы можете отфильтровать имя/статус интерфейса, используя grep
поиск строк, начинающихся с цифры:
user@host$ ip link show | grep "^[0-9]"
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
Активные интерфейсы имеют слово UP, поэтому, чтобы получить активный, отфильтруйте локальный интерфейс localhost(lo:):
user@host$ ip link show | grep "^[0-9]" | grep -v "lo: " | grep "UP"
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
Нам нужно только имя интерфейса, второе слово:
user@host$ ip link show | grep "^[0-9]" | grep -v "lo: " | grep "UP" | cut -d ':' -f 2
ens32
Вы можете сохранить этот результат в некоторой переменной (в Bash):
ACTIVEIF=$(ip link show | grep "^[0-9]" | grep -v "lo: " | grep "UP" | cut -d ':' -f 2)
Конечно, если у вас более одного активного интерфейса, сохраните список в массиве имен, добавив круглые скобки и пробелы вокруг результата. Например(теперь я не буду фильтровать lo :, так как у меня есть только один физический интерфейс):
ACTIVEIFACES=( $(ip link show | grep "^[0-9]" | grep "UP" | cut -d ':' -f 2) )
Для проверки содержимого переменной массива:
user@host$ set | grep ^ACTIVEIFACES
ACTIVEIFACES=([0]="lo" [1]="ens32")
и перечислить их в сценарии:
ACTIVEIFACES=( $(ip link show | grep "^[0-9]" | grep "UP" | cut -d ':' -f 2) )
NIFACES=${#ACTIVEIFACES[@]}
if [ $NIFACES -ne 0 ] ; then
echo "There exist $NIFACES active interfaces:"
for ((i=0; i<NIFACES; i++)) ; do
echo "${ACTIVEIFACES[$i]}"
done
else
echo "There is no active interfaces detected"
fi
(Поскольку команда for
использует числовые выражения, вы можете опустить $ в $i и $NIFACES между двойными скобками ).
Вывод скрипта в моем случае::
There exist 2 active interfaces:
lo
ens32
Надеюсь, этот метод вам пригодится. Удачи!
Наивным ответом было бы отслеживать интерфейсы, но интерфейс уровня -2 будет регистрироваться как «работающий», когда он подключен к (Ethernet )или связанному (Wi-Fi ), но это сам по себе не говорит вам, будет ли он использоваться для передачи трафика.
Вместо этого может быть более эффективным отслеживать изменения маршрута по умолчанию (с ).
Команду ip mon
можно использовать для отслеживания изменений, хотя она также дает регулярные обновления статуса, даже если кажется, что ничего не изменилось, поэтому вы должны быть готовы их игнорировать.
(Рекомендуется использовать опцию -o
, чтобы каждый отчет располагался на одной строке; это значительно упрощает синтаксический анализ.)
#!/bin/bash
ip -o mon |
sed -e 's/\\/ /g
s/ */ /g
s/^\(Deleted \|\)\([0-9]*\): \([^ :]*\) /\1addr \2 \3 /
s/^\(Deleted \|\)\([0-9]*\): \([^ :]*\): /\1link \2 \3 / ' |
while
IFS=' ' read -ra line
do
if [[ ${line[0]} = Deleted ]]
then
mode=delete
line=( "${line[@]:1}" ) # shift(line)
else
mode=update
fi
case "${line[*]}" in
addr) # added by 'sed' above
device_num=${line[1]}
device_name=${line[2]}
family=${line[3]} # 'inet' or 'inet6'
ip_address=${line[4]}
#... handle address changes ...
;;
link) # added by 'sed' above
device_num=${line[1]}
device_name=${line[2]%:}
state=${line[3]} # eg '<BROADCAST,MULTICAST,UP,LOWER_UP>'
#... handle link UP/DOWN...
;;
default)
#... handle default route changes...
;;
prefix | local | broadcast | multicast | throw | unreachable | prohibit | blackhole )
#... handle other route changes...
;;
esac
done