об этих строках:
iptables -A INPUT -p tcp --dport 8090 -j DROP
iptables -A INPUT -p tcp --dport 8090 -s <IP> -j ACCEPT
вам следует изменить их порядок, потому что IPTables правила перезаписывают друг друга в состоянии конфликта, и это правильный способ, поэтому сначала исправьте их и проверьте все остальные роли, чтобы предотвратить перезапись.
относительно NAT части вашего вопроса, неясно, однако в докере вы должны назначать порт при создании контейнера:
docker run... -p 8090:8080...
Вы можете явно захватить еще два поля с разделителями:
$ sed -r 's/(.*);([^;]*;[^;]*;)/\1,\2/' input_file.csv
1;2;3;4;5;6,7;8;9
10;20;30;40;50;60,70;80;90
100;200;300;400;500;600,700;800;900
или более программно
$ sed -r 's/(.*);(([^;]*;){2})/\1,\2/' input_file.csv
1;2;3;4;5;6,7;8;9
10;20;30;40;50;60,70;80;90
100;200;300;400;500;600,700;800;900
где число в квантификаторе {n-1}
заменяет n-е от последнего.
Вы можете просто поменять местами строки, изменить N-е вхождение, а затем повторно -поменять местами:
rev file | sed 's/;/,/3' | rev
sed
хорош, когда вы работаете со строками целиком, но awk
и perl
лучше, когда вам нужно работать с полями/столбцами внутри строки.
$ perl -F';' -lane 'splice @F,-4,2,join(",",@F[-4..-3]); print join(";",@F)' input.csv
1;2;3;4;5;6,7;8;9
10;20;30;40;50;60,70;80;90
100;200;300;400;500;600,700;800;900
Это разбивает строку на массив @F, используя ;
в качестве разделителя. Затем он заменяет четвертое -последнее и третье -последнее поля одной строкой, содержащей значения обоих полей, разделенных запятой.
Затем он печатает весь массив @F с запятой -в качестве разделителя полей.
splice
— встроенная в Perl -функция манипулирования массивами общего назначения. Есть несколько форм его использования, но я использую здесь форму:
splice ARRAY,OFFSET,LENGTH,LIST
т.е.
splice @F, -4, 2, join(",",@F[-4..-3])
ARRAY
:@F, массив Perl по умолчанию при использовании с параметрами -F
или -a
, аналогичный $1, $2, awkНомера полей за 3 доллара. OFFSET
:-4, четвертое последнее поле LENGTH
:2, два поля (, то есть $F[-4]
и$F[-3]
)LIST
:в этом случае "СПИСОК" имеет только один элемент, строку, содержащую значения полей -4 и -3, соединенные запятой. Однако в общем случае LIST может быть массивом любой длины, поэтому splice
также можно использовать для вставки дополнительных полей в массив. Подробнее см. perldoc -f splice
.
Кроме того, @F[-4..-3]
— это то, что в Perl известно как срез массива. Оператор диапазона ..
возвращает элементы полей от -4 до-3. Для этого скрипта его также можно было бы записать как @F[-4,-3]
, то есть элементы -4 . ] и-3. Срезы массива могут быть указаны с помощью диапазонов и/или списков.
Использованиеgawk
:
awk -F';' '{print gensub(";", ",", NF-3)}'
gawk
, построенный -в функции gensub()
, заменяет точку с запятой от n до последней запятой.
С помощью GNU sed
мы можем сделать следующее.
sed -e '
s/;/&/3;T
y/;/\n/
:a;s/\n/&/4;tb
s//,/;y/\n/;/
:b;s//;/;ta
' file
1;2;3;4;5;6,7;8;9
10;20;30;40;50;60,70;80;90
100;200;300;400;500;600,700;800;900
С помощью Perl
мы разделяем, а также записываем разделители полей в разделенный массив (@F ). Тогда 6-е поле с конца - это 3-я точка с запятой с конца, которую мы меняем на запятую. Остальное без изменений.
perl -aF'(;)' -plse '
$F[-6]=",",s/.*/@F/ if @F >= 6;
' -- -\"=./file
Используя POSIX awk, мы изменяем разделители в зависимости от их положения:
awk -F\; -v n=3 '{ for(i=1; i<=NF; i++) printf "%s%s", $i, (i==NF-n?",":(i==NF?ORS:FS)) }' infile
Вариант ответа steeldriver , который закрепляет шаблон в конце строки и, следовательно, может использовать3
(или любой другой номер, n
, вам нужно использовать ), а не2
(т.е.n-1
)для подсчета повторов конечных полей, если на самом деле существует столько полей. Его также не волнуют начальные данные в строке перед разделителем, который мы хотим заменить.
Использование стандартаsed
:
sed 's/;\(\([^;]*;\{0,1\}\)\{3\}\)$/,\1/' file
Использование расширенного регулярного выражения в sed
реализациях, которые его поддерживают:
sed -E 's/;(([^;]*;?){3})$/,\1/' file
Любое выражение соответствует последним трем полям. Вложенное выражение -([^;]*;?)
будет соответствовать строке, которая не содержит символа ;
, а затем может заканчиваться одним таким символом. Последнее поле в строке не заканчивается на ;
, так что это позволяет нам сопоставить это поле и по-прежнему привязывать полное выражение к концу строки.
Это, как и большинство sed
решений, не будет работать, если какое-либо поле содержит встроенные;
символы или символы новой строки (, которые разрешены в CSV-файлах ).
Использование синтаксического анализатора CSV для преобразования данных в формат JSON, их изменение с помощью jq
и последующее преобразование обратно в файл CSV с правильными разделителями. Это справится с данными, содержащими встроенные разделители, символы новой строки и кавычки :
csvjson -H -d ';' file |
jq -r --argjson n 3 '.[] | [.[]] |.[-($n+1):(if $n > 1 then -($n-1) else null end)]] |= [join(",")] | @csv' |
csvformat -H -D ';'
Здесь используется csvkit
для преобразования CSV в JSON. Затем он импортирует значение 3
в переменную jq
n
в командной строке и использует ее для объединения двух полей на основе этого значения. Измененные данные затем возвращаются обратно в CSV и переформатируются для использования ;
в качестве разделителей с самого начала.
Учитывая файл CSV с четырьмя столбцами и четырьмя строками,нравится
A;B;C;D
1;"2.1;2.2";3;4
1;2;"3.1
3.2
3.3";4
1;"And then I said ""2 2 2""";3;4
второй разделитель с конца заменяется на запятую (эффективно объединяет 2-е и 3-е поля в одно поле):
$ csvjson -H -d ';' file | jq -r --argjson n 2 '.[] | [.[]] |.[-($n+1):(if $n > 1 then -($n-1) else null end)] |= [join(",")] | @csv' | csvformat -D ';'
A;B,C;D
1;"2.1;2.2,3";4
1;"2,3.1
3.2
3.3";4
1;"And then I said ""2 2 2"",3";4
sed -E 's/;([^;]*(;[^;]*){2})$/,\1/' file
Если вам нужно начать с конца , используйте конец($
)в качестве привязки для регулярного выражения.
Перед концом нам нужно сопоставить некоторые не-;
символы, которым предшествует;
:
;[^;]*$
Если мы повторим это три раза, мы доберемся до 3-го до последнего;
:
;[^;]*;[^;]*;[^;]*$
Затем мы можем зафиксировать то, что нужно заменить:
s/;\([^;]*;[^;]*;[^;]*\)$/,\1/
Или, сделав количество повторяющихся секций числом(n-1
):
sed 's/;\([^;]*\(;[^;]*\)\{2\}\)$/,\1/' file
Или, чтобы удалить кратное \
, используйте расширенное регулярное выражение:
sed -E 's/;([^;]*(;[^;]*){2})$/,\1/' file