#linux #awk
Вопрос:
Я написал команду awk
awk 'NR==5 {sub(substr($1,14,1),(substr($1,14,1) 1)); print "test.py"}' > test.py
Это попытка изменить 14-й символ в 5-й строке файла python. По какой-то причине это не прекращает выполнение, и я должен его прервать. Это также удаляет содержимое файла.
Пример ввода:
import tools
tools.setup(
name='test',
tagvisc='0.0.8',
packages=tools.ges(),
line xyz
)
`
Вывод:
import tools
tools.setup(
name='test',
tagvisc='0.0.9',
packages=tools.ges(),
line xyz
)
Комментарии:
1. Что вы пытаетесь сделать? Предоставьте пример ввода с ожидаемым результатом.
2. @anubhava добавил это
3. существует также скрытая проблема с
sub
, предположим, у вас есть значение3.4.3
. Это увеличит первое вхождение 3.4. Вам нужно будет использовать
split()
, чтобы разделить это поле на массив, а затем увеличить и собрать его обратно. См. Руководство пользователя GNU Awk — Функции обработки строк5. Я бы выбрал Perl, здесь,
perl -i -pe 's/^h*tagvisc='"'"'d .d .Kd /($amp; 1)/e' test.py
, или, если строка важна,perl -i -pe 's/^h*tagvisc='"'"'d .d .Kd /($amp; 1)/e if $. == 5' test.py
Ответ №1:
Если я понимаю нюансы того, что вам нужно сделать сейчас, вам нужно будет разделить первое поле 5-й записи на массив, используя "."
в качестве fieldsep, а затем удалить "","
из конца 3-го элемента массива (необязательно), прежде чем увеличивать число и собирать поле обратно. Вы можете сделать это с помощью:
awk '{split($1,a,"."); sub(/["],/,"",a[3]); $1=a[1]"."a[2]"."(a[3] 1)"","}1'
( NR==5
например, опущено)
Пример использования / вывода
$ echo 'tagvisc="3.4.30"', |
awk '{split($1,a,"."); sub(/["],/,"",a[3]); $1=a[1]"."a[2]"."(a[3] 1)"","}1'
tagvisc="3.4.31",
Я оставлю перенаправление на временный файл, а затем вернусь к оригиналу. Дайте мне знать, если это не то, что вам нужно.
Добавив NR == 5
, что у вас будет
awk 'NR==5 {split($1,a,"."); sub(/["],/,"",a[3]); $1=a[1]"."a[2]"."(a[3] 1)"","}1' test.py > tmp; mv -f tmp test.py
Комментарии:
1. он добавляется
..1
к каждой строке. Я думаю, нам придется указать номер строки2. Вам нужно добавить
NR==5
условие — я оставил его для примера. Также обратите внимание, что я исправил опечатку","
"."
междуa[2]
иa[3]
3. На самом деле вы можете использовать
'{split($1,a,"."); $1=a[1]"."a[2]"."(a[3] 1)"","}1'
asawk
, чтобы отбросить конечные нецифровые значения при преобразовании в числовое значение при добавлении1
.4. Хорошо, это работает, но в файле есть несколько пробелов перед строкой, из-за чего они исчезают.
5. Да, есть несколько способов справиться с этим, ни один из них не является тривиальным. Причина в том, что вы используете значение по умолчанию
FS
, которое разделяет поля на пробелы. Множественные пробелы обрабатываются как один разделитель. Вы можете сохранить количество начальных пробелов$0
и добавить их обратно, если это требуется.
Ответ №2:
Отойдите от фиксированного номера строки ( NR==5
) и фиксированной позиции символа ( 14
) и вместо этого посмотрите на динамический поиск того, что вы хотите изменить / увеличить, например:
$ cat test.py
import tools
tools.setup(
name='test',
tagvisc='0.0.10',
packages=tools.ges(),
line xyz
)
Одна awk
идея увеличить 10
(3-я строка, 3-я числовая строка в строке):
awk '
/tagvisc=/ { split($0,arr,".") # split line on periods
sub("." arr[3] 0 "47","." arr[3] 1 "47") # replace .<oldvalue>47 with .<newvalue>47; 47 == single quote
}
1
' test.py
Примечания:
arr[3]
=10',
; witharr[3] 0
awk
возьмет самое левое полностью числовое содержимое, удалит все остальное, затем добавит0
, оставив намarr[3]
=10
; та же логика применяется дляarr[3] 1
(arr[3] 1
=11
); в основном трюк для отбрасывания любого суффикса, который не является числовым- если в файле есть несколько строк со строкой
tagvisc='x.y.z'
, это изменитсяz
во всех строках; мы можем обойти это, добавив еще немного логики, чтобы изменить толькоfirst
вхождение, но я пока оставлю это, предполагая, что это не проблема
Это генерирует:
import tools
tools.setup(
name='test',
tagvisc='0.0.11',
packages=tools.ges(),
line xyz
)
Если цель состоит в том, чтобы перезаписать исходный файл новыми значениями, у вас есть пара вариантов:
# use temporary file:
awk '...' test.py > tmp ; mv tmp test.py
# if using GNU awk, and once accuracy of script has been verified:
awk -i inplace '...' test.py
Комментарии:
1. Я отлаживаю, но это не вносит никаких изменений в мой файл.
2. вы используете временный файл или
awk -i inplace
?3. Да, с использованием файла tmp
4. пожалуйста, обновите вопрос первыми 7 строками вашего файла
5. обновлен ответ; лучше всего предоставить пример фактического файла, иначе мы ходим по кругу, когда наши предложения основаны на неверных данных
Ответ №3:
Использование awk для внесения изменений в n-й символ в [m-й] строке файла:
$ awk 'BEGIN{FS=OFS=""}NR==5{$18=9}1' file # > tmp amp;amp; mv tmp file
Выводит:
import tools
tools.setup(
name='test',
tagvisc='0.0.9', <----- this is not output but points to what changed
packages=tools.ges(),
line xyz
)
Объяснено:
$ awk '
BEGIN {
FS=OFS="" # set the field separators to empty and you can reference
} # each char in record by a number
NR==5 { # 5th record
$18=9 # and 18th char is replaced with a 9
}1' file # > tmp amp;amp; mv tmp file # output to a tmp file and replace
Обратите внимание: некоторые awk (возможно, все, кроме GNU awk) завершатся ошибкой, если вы попытаетесь заменить многобайтовый символ на однобайтовый (например, utf8 ä
(0xc3 0xa4) на a
(0x61), что приведет к 0x61 0xa4). Естественно ä
, перед позицией, которую вы хотите заменить, ваши вычисления будут отклонены на 1.
О да, вы можете заменить один символ несколькими символами, но не наоборот.
Ответ №4:
что-то вроде этого…
$ awk 'function join(a,k,s,sep) {for(k in a) {s=s sep a[k]; sep="."} return s}
BEGIN {FS=OFS="""}
/^tagvisc=/{v[split($2,v,".")] ; $2=join(v)}1' file > newfile
Ответ №5:
Использование GNU awk для 3-го аргумента для сопоставления () и редактирования «на месте»:
$ awk -i inplace '
match($0,/^([[:space:]]*tagvisc=47)([^47] )(.*)/,a) {
split(a[2],ver,".")
$0 = a[1] ver[1] "." ver[2] "." ver[3] 1 a[3]
}
{ print }
' test.py
$ cat test.py
import tools
tools.setup(
name='test',
tagvisc='0.0.9',
packages=tools.ges(),
line xyz
)