LINUX.ORG.RU

#!bin/Bash, awk , поиск и замена строки в файле .

 , , , ,


2

3

Здравствуйте! Недавно начал учится писать скипты и не всё ещё получается, прошу помочь с проблемой.

Необходимо в файле найти и заменить строку в определённом блоке файла. Файл разделён на блоки.Пример файла :

[1]
rule= 1 ip icmp all la la la la
[2]
rule= 1 ip icmp all la la la la
rule= 2 vpn to all la la la la
[3]
rule= 1 ftp ip vpn la la la la
, необходимо по заданному блоку 1, 2 или 3 найти строку и заменить её на другую.

Входящими параметрами получается будет: путь файлы для редактирования блок в котором надо изменить старая строка новая строка.

написал не до конца скрипт, дальше не смог :((

#!/bin/bash

#param1 = /etc/user/f.conf
#param2 = editing block  [example]: 1
#param3 = newRule  [exaple]: rule= num 2 icmp from ip 
#param4 = oldRule  [exaple]: rule= num 3 icmp from ip to 


Filelocation=$1
shift
Block=$1
shift
newRule=$1
shift
oldRule=$@

error_exit() {
	echo $@
	exit 1
	return 1
}

backup_orig_file() {
	backup_dir=`echo "/backup/orig_file"`
	mkdir -p $backup_dir || error_exit "Directory $backup_dir not created"
	cp $1 $backup_dir
	return 0
}

insert_line() {
	Filelocation=$1
	shift
	Block=$1
	shift
	newRule=$1
	shift
	oldRule=$@		
	
	Block_line_num=`cat $Filelocation | grep -n $Block | cut -d ":" -f 1`

	old_line_num=`cat $Filelocation | grep -n $oldRule | cut -d ":" -f 1`

###############################	
	if [old_line_num>Block_line_nem && мы не дошли до след. блока "[" или не дошли до eof  ];then
	
	на место old_lline_num вставить newRule
	
###############################
	else
		if [ old_line_num!= 0 ]; then
			
		else
			echo "Rule not found in the Block :---- $Block -----"
		fi	
	fi
	ruturn 0
	}

if [ -e $Filelocation ]; then
	echo "File exist"
else
	echo "File $FILE_NAME not exist"
	exit 1
fi

case "$Block" in
	1) echo "1 selected";shift;;
	2) echo "2 selected";shift;;
	3) echo "3 selected";shift;;
	4) echo "4 selected";shift;;
	5) echo "5 selected";shift;;
	6) echo "6 selected";shift;;
	7) echo "7 selected";shift;;
	*) echo "Selection not recognized"; exit 1;;
esac

backup_orig_file $Filelocation

insert_line $Filelocation $Block $newRule $oldRule

exit 0



Последнее исправление: cetjs2 (всего исправлений: 1)

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

dmitry_malikov ★★
()

Как я понял исходные данные вы привели, теперь приводите ожидаемый результат, а там Дима, как гуру sed'a вас порадует очередным шедевром.
Если же упражнение заключается в написании скрипта на баше, то так и скажите, не будем зря человека напрягать

zolden ★★★★★
()

можно авк: там можно нормально переменные внутрь передавать

#!/bin/dash

awk -v num="$1" -v old="$2" -v new="$3" \
    -v RS='\\[[0-9]+\\]\\n' -v ORS="" '
 NR == 1 { next };
 { block = NR - 1; printf "[%s]\n", block }
 block == num { sub(old, new) }
 { print }
 END { printf "\n" }
'

xsel -o | /tmp/a.sh 2 «ip icmp» «IP ICMP» заменяет во втором

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

файл до скрипта :

[1]
rule= 1 ip icmp all la la la la
[2]
rule= 1 ip icmp all la la la la
rule= 2 vpn to all la la la la
[3]
rule= 1 ftp ip vpn la la la la
Нужно запустить файл с входящими значениями :

#param1 = /etc/user/f.conf #param2 = editing block [example]: 2 #param3 = newRule [exaple]: rule= num 2 icmp from ip #param4 = oldRule [exaple]: rule= 1 ip icmp all la la la la

файл после скрипта:

[1]
rule= 1 ip icmp all la la la la
[2]
rule= num 2 icmp from ip
rule= 2 vpn to all la la la la
[3]
rule= 1 ftp ip vpn la la la la

буду рад если это будет круто написан в sed'e

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

да легко:

$ cat in
[1]
rule= 1 ip icmp all la la la la
[2]
rule= 1 ip icmp all la la la la
rule= 2 vpn to all la la la la
[3]
rule= 1 ftp ip vpn la la la la
$ cat run.sh 
#!/bin/bash

sed "/\[$1\]/,/\[.*\]/s/$2/$3/" $4
$ ./run.sh 2 "rule= 1 \([^ ]*\) \([^ ]*\) .*" "rule= num 2 \2 from \1" in
[1]
rule= 1 ip icmp all la la la la
[2]
rule= num 2 icmp from ip
rule= 2 vpn to all la la la la
[3]
rule= 1 ftp ip vpn la la la la

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

можно и проще, без файла run.sh:

$ sed "/\[2\]/,/\[.*\]/s/rule= 1 \([^ ]*\) \([^ ]*\) .*/rule= num 2 \2 from \1/" in
[1]
rule= 1 ip icmp all la la la la
[2]
rule= num 2 icmp from ip
rule= 2 vpn to all la la la la
[3]
rule= 1 ftp ip vpn la la la la

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

это я как понимаю можно сделать если заранее известно как выглядит наш файл , а если мы не знаем сколько и каких правил в каждом блоке, известно что если и есть правило , то его надо заменить на новое.

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

В $3 любая часть блока, как понял, так и написал.

Если нужно точное совпадение: либо разделять блок на строки, либо (что лучше), задвать блок так (в $0 будет одно из правли блока):

awk -v num="$1" -v old="$2" -v new="$3" '
/^\[[0-9]+\]$/ { block = substr($0,2,length($0)-2); print; next }
...'
anonymous
()
Ответ на: комментарий от Scaurus

правильное unix-way решение - отдельная утилита, написанная на любимом языке (или честно взятая с аналогичного проекта) для манипуляций с ini-файлами. А на bash - системная логика проекта.

сейчас вы 100% столкнётесь с тем что при сравнении надо удалять/игнорировать лишние пробелы и табуляции, далее наверняка надо будет искать дублированные правила, а потом логично уметь сравнивать конфиги и проверять их корректность.

а на то чтобы сделать удобный инструмент достаточно одного дня.

MKuznetsov ★★★★★
()
27 февраля 2014 г.
case "$Block" in
	1) echo "1 selected";shift;;
	2) echo "2 selected";shift;;
	3) echo "3 selected";shift;;
	4) echo "4 selected";shift;;
	5) echo "5 selected";shift;;
	6) echo "6 selected";shift;;
	7) echo "7 selected";shift;;
	*) echo "Selection not recognized"; exit 1;;
esac

зачётно

emulek
()
Ответ на: комментарий от zolden

а там Дима, как гуру sed'a вас порадует очередным шедевром. Если же упражнение заключается в написании скрипта на баше, то так и скажите, не будем зря человека напрягать

есл это вдруг про меня, то я и на bash'е срать умею.

emulek
()
Ответ на: комментарий от MKuznetsov

правильное unix-way решение - отдельная утилита, написанная на любимом языке

детка, уползи в своё маздайный адъ.

сейчас вы 100% столкнётесь с тем что при сравнении надо удалять/игнорировать лишние пробелы и табуляции, далее наверняка надо будет искать дублированные правила, а потом логично уметь сравнивать конфиги и проверять их корректность.

столкнулся, и понял, что это не твоё?

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