Я не уверен, что понимаю Вашу проблему полностью, но как насчет:
$ nc 111.222.233.244 1234 \
| tee -a /tmp/stream.dump \
| while ! do_something_here; do : ; done
Кроме очевидного дампа потока в файл с tee
(добавление, так как сеть может быть разъединена по различным причинам, и Вы не могли бы обязательно хотеть перезаписывать предыдущую часть потока), это будет повторно метать икру do_somehing_here
если это не выходит правильно. Следовательно, если do_somehing_here
например, сценарий обертки, можно уничтожить то, что он на самом деле называет, который заставляет сценарий выйти неправильно и быть повторно порожденным сразу же. При редактировании сценария прежде, чем уничтожить его обработка потока может быть изменена без повторного подключения.
С помощью sed
, если вы можете отформатировать файл в виде сценария sed
, вы можете сделать это автоматически. Следующее должно работать с GNU sed
. С BSD sed
это сработает, если вы сделаете -i '' -e
для второго вызова sed
....
sed -ne's|[]\*&^.$/[]|\\&|g' \
-e's|..*|/^@&",/d|p' <./list.txt |
sed -ie'h;s/[^,]*[^@]*//' -f- -eg ./data.txt
Если вы сделаете...
-e's|..*|/^@&",/Id|p' ...
...во второй строке GNU sed
будет d
elete соответствовать любой строке в регистре list.txt
нечувствительно, но это будет равносильно синтаксической ошибке с большинством других.
Он пытается оптимизировать совпадения, удаляя первое поле и все до первого @
во втором поле во главе скрипта, который он запускает для каждой строки, затем проверяет совпадения, и, если строка проходит через все из них, g
ets копию строки, которую он сохранил в верхней части скрипта в h
старом месте. Таким образом, sed
не нужно /^[^,]*,[^,]*.../
для каждого совпадения. Если list.txt
очень длинный, то, несмотря на это, процесс не будет быстрым. В этом случае grep -F
следует отдать предпочтение (и, вероятно, в этом случае).
Как sed
, так и grep
можно заставить работать лучше - и во многих случаях значимо , так что, если используемая кодовая страница уменьшена в размере. Например, если вы в данный момент находитесь в UTF-8 локали, то выполнение:
( export LC_ALL=C
sed -ne's|[]\*&^.$/[]|\\&|g' \
-e's|..*|/^@&",/Id|p' |
sed -ie'h;s/[^,]*[^@]*//' -f-\
-eg ./data.txt
) <./list.txt
... может изменить ситуацию к лучшему - вместо того, чтобы рассматривать в качестве совпадений какие-то umpteen-тысячи различных символов, регекс-движку нужно учитывать только 128 возможностей. Это никак не должно повлиять на результат - каждый чар является байтом в C-локации и все будет учтено.
sed -i
не является надежным переключателем для использования в лучших случаях, и его следует избегать, если это вообще возможно.
Для этого w/ grep
и sed -i
:
( export LC_ALL=C
cut -d\" -f4 | cut -d@ -f2 |
grep -Fixnf ./list.txt |
sed -e's|:*\([0-9]*\).*|:\1|p'\
-e's||\1!{p;n;b\1|p' \
-e's||};n|' |
sed -nif- -e:n -e'p;n;bn' \
./data.txt
) <./data.txt
Это самый быстрый способ, который я могу себе представить, используя sed
's -i
. Он ломается следующим образом:
cut | cut
cut
s уменьшают ваши входные строки ./data.txt
от/до.... "foxva****omes****","scott@hotmail.com","8*** Rd","Ne***ah","Wi***in","54***","*******"
hotmail.com
grep
grep
может затем сравнить этот вход с каждой линией в своем образце -f
ile -перечне. txt
используя регистр -i
nsensitive -F
ixed string -x
вся строка совпадает и сообщает о том, что строка -n
umber находится в начале каждой строки его вывода. sed -e
sed
полосы grep
выводят только номера строк и записывают другой сценарий sed
, который выглядит как (учитывая гипотетические grep
совпадения на строках 10 и 20) : :10
10!{p;n;b10
};n
:20
20!{p;n;b20
};n
sed -inf-
Последний sed
читает -
stdin как свой скрипт и выполняет его только один раз - он не выполняет скрипт для каждой входной строки, как это обычно делается в скриптах w/ sed
, а выполняет скрипт в первый и единственный раз, когда он проходит через входную строку - и ему нужно всего лишь попробовать один тест на каждую входную строку.
В нашем предыдущем примере для строк 1-9 sed
сделает:
!
не 10
, {
, а p
протяните токовую строку, перезапишите токовую строку с помощью n
ext input line, и b
ранчо вернётся к метке :
с именем 10
. и для последней серии строк sed
будет p
rint; затем перезапишите текущую строку с n
ext, ранчо b
на метку :n
до тех пор, пока оно не перезапишет все входные данные.
Это не работает, если ./data.txt
очень большой, потому что sed
застрял в попытке обработать входной файл скрипта намного больше, чем он может надежно обработать. Обходной путь заключается в том, чтобы принимать входные данные в кусочках. Этот может быть надежно обработан - даже в конвейере - если вы используете правильный тип читателя. dd
- это тот самый читатель.
Я создал такой тестовый файл:
sh -c ' _1=\"foxva****omes****\",\"scott@
_2='\''","8*** Rd","Ne***ah","Wi***in","54***","*******"'\''
n=0
for m do printf "$_1%s$_2\n$_1$((n+=1))not_free.com$_2\n" "$m"
done
' $(cat ~/Downloads/list.txt) >/tmp/data.txt
...где list.txt
- здесь - по вашему -другому вопросу . Он делает каждую другую строку, как...
"foxva****omes****","scott@11mail.com","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","scott@1not_free.com","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","scott@123.com","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","scott@2not_free.com","8*** Rd","Ne***ah","Wi***in","54***","*******"
Затем я довёл его до чуть более 80 мб, как...
while [ "$(($(wc -c <data.txt)/1024/1024))" -lt 80 ]
do cat <<IN >./data.txt
$( cat ./data.txt ./data.txt)
IN
done
ls -hl ./data.txt
wc -l <./data.txt
-rw-r--r-- 1 mikeserv mikeserv 81M Jul 19 22:22 ./data.txt
925952
... а потом я...
( trap rm\ data.tmp 0; export LC_ALL=C
<./data.txt dd bs=64k cbs=512 conv=block |
while dd bs=64k cbs=512 conv=unblock \
count=24 of=./data.tmp
[ -s ./data.tmp ]
do
<./data.tmp cut -d\" -f4 | cut -d@ -f2 |
grep -Fixnf ./list.txt |
sed -e's|:*\([0-9]*\).*|:\1|p' \
-e's||\1!{p;n;b\1|p' \
-e's||};n|' |
sed -nf- -e:n -e'p;n;bn' ./data.tmp
done 2>/dev/null
)| wc -l
1293+1 records in
7234+0 records out
474087424 bytes (474 MB) copied, 21.8488 s, 21.7 MB/s
462976
Прямо здесь видно, что весь процесс занял 22 секунды, и что счетчик выходной строки как минимум верный - 462976 - это половина 925952 и вход должен был выйти вдвое меньше.
Методика работает, потому что dd
читает и записывает в байт - даже через трубку, если вы знаете, о чем говорите. И можно даже пробить ввод по строке с той же степенью точности, если можно надежно conv
ert по максимальной длине строки block
-размером (что здесь 512, или {_POSIX_LINE_MAX}
).
Воображаемый читатель может справедливо предположить, что та же самая техника может быть применена к потоку любого вида - даже вида live-log - с небольшим изменением здесь или там (а именно, чтобы сделать это безопасно, первые аргументы dd
должны измениться с bs=
на obs=
). В любом случае, однако, вам понадобится некоторая уверенность в максимальном размере входной строки, и, если строка может законно заканчиваться символом <пробела>, дополнительный механизм фильтрации, вставленный перед процессами dd
для защиты от удаления трейлинговых <пространств> с помощью dd conv=unblock
(который работает путем удаления всех трейлинговых пустот для каждого cbs
-размерного conv
-блока стирания и добавления \n
ewline). tr
и (un|)expand
приходят мне на ум как вероятные кандидаты на такой фильтр.
Это не самый быстрый способ - для этого нужно посмотреть на -m
erge sort
-операцию, я ожидаю, но она довольно быстрая, и будет работать с вашими данными. Правда, это вроде как нарушает -i
, но я думаю, что это будет правдой, куда бы вы ни пошли.
Вы можете решить эту проблему несколькими способами. Во-первых, sed
поддерживает несколько выражений за один запуск:
sed -i -e '/^[^,]*,[^,]*hotmail/Id' -e '/^[^,]*,[^,]*gmail/Id' -e '/^[^,]*,[^,]*yahoo/Id' data.txt
Вы также можете сделать это в одном выражении:
sed -i -e '/^[^,]*,[^,]*\(hotmail\|gmail\|yahoo\)/Id' data.txt
Обратите внимание, что (
, )
и |
, все должны быть экранированы.