LINUX.ORG.RU
решено ФорумAdmin

Получить значение из файла, посчитать и заменить в файле через консоль

 , ,


0

1

Приветствую всех зашедших, прошу помощи в следующей задаче.

Есть файл: /path/data.txt

В файле текстовое содержимое:

Hello this is some text
text text value:100 text text
Still some text

Размер текста около 80-100 Kb (возможно для какого-то решения размер будет иметь значение)

Вопрос. Как с помощью командной строки сделать следующее:
1. Получить из файла /path/data.txt текст value:100
2. Прибавить к полученным 100 еще 50 (получить 150). Цифра 50 должна назначаться через аргумент и может являться любым целым числом.
3. Заменить value:100 на value:150 в вышеуказанном файле.

Следующая информация может оказаться полезной:
- Номер строки, где размещено изначальное значение value:100 известно заранее. То есть не нужно искать по всему файлу.
- Весь другой текст в файле меняется
- Эти команды будут выполняться бесконечно в фоновом режиме. То есть скорость выполнения и нагрузка имеет значение.

И при всех этих действиях не ругаться, если такого файла не оказалось или в файле не оказалось такой value:100. То есть просто проигнорировать.

Если у кого есть решение, прошу подсказать. Спасибо

Можно использовать gawk с опцией -i (inplace).

anonymous
()

Маловероятно что здесь кто то напишет скрипт за тебя.

man sed
На твоем месте я бы посмотрел в сторону python или других скриптовых ЯП.

zyxar
()

Ты расписал в красках что ты хочешь сделать, но забыл написать зачем. Как теперь прикажешь стебаться над идиотским решением?

Ты шаблон изобретаешь что ли?

$ cat > 1.sh
value=$1

$ cat > 2.sh
. ./1.sh
cat <<EOF
Hello this is some text
text text value:$value
Still some text
EOF

$ sh  2.sh 100
Hello this is some text
text text value:100
Still some text

$ sh  2.sh 150
Hello this is some text
text text value:150
Still some text

Это просто демонстрация принципа: не правь, а гнерируй.

anonymous
()
Ответ на: комментарий от zyxar

Да, вчера реализовал все на sed и grep. Но это оказалось настолько медленно, что даже реализация на PHP все делала быстрее.

Кто будет читать или искать подобное, мой вам совет - используйте серверные языки. Даже самый не быстрый язык делает это быстрее.

Для сравнения: 1000 итераций на sed+grep = ~14 сек, PHP (не оптимизированный код) - 1 сек.

antobra
() автор топика
Ответ на: комментарий от anonymous

Спасибо, да, лучше использовать серверные языки.

antobra
() автор топика

man powershell

anonymous
()
Ответ на: комментарий от antobra

Да, вчера реализовал все на sed и grep. Но это оказалось настолько медленно, что даже реализация на PHP все делала быстрее.

Проблема реализации. Не понятно зачем нужна смесь grep и sed. «Или крестик или трусы»
Не голословное утверждение. В такой связке скорее всего и будет дикое падение скорости. Проходил на практике. Однако если уложите в тот же sed (при возможности) тот пых будет нервно курить в сторонке.

anc ★★★★★
()
Ответ на: комментарий от antobra

Для сравнения: 1000 итераций на sed+grep = ~14 сек, PHP (не оптимизированный код) - 1 сек.

Для интереса накостылял:

cat ./out.txt
Hello this is some text
text text value:100 text text
Still some text
Hello this is some text
text text value:100 text text
Still some text
...
итого 999 строк
cat ./2.sh
#!/bin/sh
A=50
F='./out.txt'
cat $F | \
sed -r "s/(.*)(value:)([0-9]+)(.*)/echo \1\2\$(( \3 + $A ))\4/e"

time ./2.sh
Hello this is some text
text text value:150 text text
Still some text
Hello this is some text
text text value:150 text text
Still some text
.... 
real	0m0.575s
user	0m0.304s
sys	0m0.064s

anc ★★★★★
()
Ответ на: комментарий от anc

Простите забыл про

- Номер строки, где размещено изначальное значение value:100 известно заранее. То есть не нужно искать по всему файлу.

Все тоже самое но с номером строки

real	0m0.022s
user	0m0.007s
sys	0m0.001s

anc ★★★★★
()
Ответ на: комментарий от anonymous

Строки/диапазон-строк указываются перед командами. В данном случае раз одна строка то например так

sed -r "$LINENUM s/(.*)(value:)([0-9]+)(.*)/echo \1\2\$(( \3 + $A ))\4/e"

anc ★★★★★
()
Ответ на: комментарий от Deleted

Согласен полностью. В оправдание могу только сказать что вначале было написано «накостылял». Слабое оправдание, но хоть какое-то.
''"$LINENUM"' s/(.*)(value:)([0-9]+)(.*)/echo \1\2\$(( \3 + '"$A"' ))\4/e'

anc ★★★★★
()
Ответ на: комментарий от anc

Shell'у лучше отдавать для вычисления только число.

sed -r $LINENUM'!b;h;s/.*value:([0-9]+).*/echo $((\1+'$A'))/e;T;G;s/([0-9]+)\n(.*value:)[0-9]+(.*)/\2\1\3/'
Deleted
()
Ответ на: комментарий от Deleted

Обе переменные заданы ранее, то есть известны. Но ваш «стиль» хорош, даже парсить леняво (потом наверное распарю). Редко использую смены буферов, и тем более метки (почти никогда). Так что мне с вами не равняться. Вообще ждал в этой теме еще одного знатока, но видимо с праздников он еще не отошел.

anc ★★★★★
()
Ответ на: комментарий от Deleted

Shell'у лучше отдавать для вычисления только число.

Стоп. Сходу не вижу профита в вашем варианте. Если не лениво поясните.
Спасибо!

anc ★★★★★
()
Ответ на: комментарий от anc

У вас строки из исходного файла, заключённые в `` или в $() исполняются:

$ A=50 ; LINENUM=1;  echo 'text `date` text value:100 text text' | sed -r ''"$LINENUM"' s/(.*)(value:)([0-9]+)(.*)/echo \1\2\$(( \3 + '"$A"' ))\4/e'
text Пт янв 19 21:28:47 MSK 2018 text value:150 text text

в моём варианте в shell будет передано только echo $((100+50))

$ A=50 ; LINENUM=1;  echo 'text `date` text value:100 text text' | sed -r $LINENUM'!b;h;s/.*value:([0-9]+).*/echo $((\1+'$A'))/e;T;G;s/([0-9]+)\n(.*value:)[0-9]+(.*)/\2\1\3/'
text `date` text value:150 text text

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.