LINUX.ORG.RU

Редактор текста в bash, без применения vi, sed, и т.д.

 , , ,


4

2

Добрый день, такой вопрос. Есть потребность в создании программы, для редактирования текста в потоке(аналог sed но своими ручками). Решил использовать фичу read -e -i , чтоб построчно выводить файл и менять. Встал в тупик, написав только это(в цикле не работает read). Точнее он работает, но строки пустыми выводит. Как фиксить и кто поможет? Заранее спасибо. Текст скрипта:

#!/bin/bash

while true
do
	ABSOLUTE_FILENAME=`readlink -e "$0"`
	DIRECTORY=`dirname "$ABSOLUTE_FILENAME"`
	read -e -p "Enter path to the file: " -i $DIRECTORY FILE
	echo $FILE
	read -p "PRESS 
	y - show file
	e - exit
	" work
	while read -p line 
	do
		case $work in
			y|Y) read -e -p "Edit: " -i $line text;echo $text;
			sleep 1;;
			e|E) break;;
		esac
	done < $FILE 
	break
done

Делай свое домашнее задание сам, выдумщик. Необходимость у него, лол.

anonymous ()

Для начала, перепишите скрипт в читаемый вид и оформите в lorcode. И что именно вы хотите получить?

hanharr ()
#!/bin/bash

while true
do
	ABSOLUTE_FILENAME=`readlink -e "$0"`
	DIRECTORY=`dirname "$ABSOLUTE_FILENAME"`
	read -e -p "Enter path to the file: " -i $DIRECTORY FILE
	echo $FILE
	read -p "PRESS 
	y - show file
	e - exit
	" work
	while read -p line 
	do
		case $work in
			y|Y) read -e -i "$(cat $line)" w;echo -e "$w"| tr "%" "n" > line
			;;
			e|E) break;;
		esac
	done < $FILE 
	break
done
SerGraph ()
Ответ на: комментарий от SerGraph

Прошу прощения, почему-то сразу не отправилось нормально. Нужна программа, чтобы редактировать построчно текст файла и записывать обратно. Реализация через read -e -i

read -e -i "$line" w;echo -e "$w"| tr "%" "n" > $line
Типо такого, только это обрабатывает 1 строку.

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

По сути надо в цикле правильно реализовать эту команду.(т.к. только для 1 строки работает)

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

Почему нельзя по простому?:

if [ -z "$1" ]
then
    echo "Usage: ..."
else
    cat $1 | while read tline; do ... ; done
fi

Зачем всё это нагромождение непойми чего?

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

Даже если так, как сделать построчное редактирование и сохранение в файл? Что не так?

#!/bin/bash
if [ -z "$1" ]
then
    echo "Usage: ..."
else
    cat $1 | while read line; do read -e -i "$line" w;echo -e "$w"| tr "%" "n" > $1; done
fi

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

ак сделать построчное редактирование и сохранение в файл? Что не так?

    cat "$1" | while read line; do read -e -i "$line" w;echo -e "$w"| tr "%" "n" >> "/tmp/$1"; done
    mv "/tmp/$1" "$1"

Как то так.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 2)
Ответ на: комментарий от Deleted

Меня вот смущает один нюанс. Скорее всего изначальное задание подразумевает использовать баш без утилит, в чистом виде что-ли. А то бред какой-то, вы вот вместо sed кастыль напишите(насколько сможете), но при этом можете использовать всё, что угодно.

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

Меня вот смущает один нюанс.

Меня он тоже смущает. Тока это не ко мне. Это к ТС.

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

Изначальное задание, редактирование текста файла в bash, без использования утилит(vi,sed и др). Есть только инструмент read, через него и работаю.

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

тогда уж вместо неё должен быть IFS.

Поддерживаю.

echo -e -n "${w//%/n}" >> "/tmp/$1"
Deleted ()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от SerGraph

Прошу прощения, а можно поинтересоваться для чего?
Может начальник у вас с приветом или он по объективным причинам считает что sed можно выкинуть на помойку?

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

Энивей не работает. Скрипт должен выполнять изменение строки в цикле, а потом запись в файл.В нашем случае, как у вас и у меня, он думает, что на выходе пустая строка и сохраняет пустую строку в файл. Я вторым сообщением вставлял код, который и редактирует и сохраняет, но только последнюю строку. Поэтому и спрашиваю, какое решение вы предложите. Спасибо.

read -e -p "Enter path to the file: " -i $DIRECTORY FILE

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

Я вот просто не понимаю, что именно надо получить. Я когда прибегаю к sed, то 99% случаев это работа с регулярками и вот как такое можно реализовать на чистом bash я без подумать не скажу. Возможно, у меня взгляд замылен или поспать надо.

Что значит изменение строки в цикле? Взять строку, разбить поэлементно и каждый элемент заменить перебрав массив?

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

Ну я спорить не могу.Есть условие, я подчиняюсь: 1) Ничего встроенного не использовать 2) Обрабатывать большие текстовые файлы 3) Реагировать на сочетания клавиш (ну это мне ясно хотя бы)

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

Как я понимаю: На входе большой файл Построчно считывать его и одновременно с этим, для каждой строки редактировать. Если всё в порядке, Enter, следующая строка. И так до конца файла.

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

Т.е. мы открываем файл и начинаем его построчно перебирать. Вот мы получаем строку, которую нужно изменить и просто набираем нужную нам? С поиском и заменой я похоже перегнул. :D

Но, т.к. вы написали, что именно sed нельзя, то есть ощущение, что подстроки в строках должны заменяться автоматически следуя шаблону.

hanharr ()
Последнее исправление: hanharr (всего исправлений: 2)
Ответ на: комментарий от hanharr
read -e -p "Enter path to the file: " -i $line #тут строка из файла,которую можно редактировать w # тут строка полученная после редактирования

И по моей логике это нужно зациклить и w записывать в файл построчно. Но получается в конце концов сохранить только последнюю. Для меня вообще после swift на bash прогать просто ужс. Вот и прошу как-то со мной подумать.

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

Вы поправили tr "%" "n" > line на tr "%" "n" >> line? Должно быть >>. Bash это не про прогать, это про автоматизацию и даже в этом случае иногда лучше прибегнуть к perl/python.

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

и даже в этом случае иногда лучше прибегнуть к perl/python

И всё же perl. Он изначально именно для подобного рубился.

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

Опять же условие только bash. Про zsh и другие оболочки забыть. Да изменил, ничего.

#!/bin/bash
if [ -z "$1" ]
then
    echo "Usage: ..."
else
    cat "$1" | while read line; do read -e -i "$line" w;echo -e "${w//%/n}" >> line; done
fi

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

он создаёт копию файла просто

Ничего он у тебя не создает, только переменную line по циклу гоняет. Файлом у тебя и не пахнет. Сделай проще:

#!/bin/bash
if [ -z "$1" ]
then
    echo "Usage: ..."
else
    src="$1"
    if [ -z "$2" ]
    then
        dst="$src.$$.tmp"
    fi
    cat "$src" | while read line; do echo -e "${line//%/n}"; done > "$dst"
fi
Deleted ()
Последнее исправление: Deleted (всего исправлений: 3)
Ответ на: комментарий от Deleted

Возможно я что-то не понимаю, но что делает это программа? Редактирования я не вижу. Вообще не понимаю зачем создавать tmp файл.

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

но что делает это программа?

Ни какой программы, это набор команд - скрипт.

Что делает каждая команда? Так посмотри сам и подгони под себя. Например:

echo "бла-бла-бла%%" | while read line; do echo -e "${line//%/n}"; done
Deleted ()
Ответ на: комментарий от SerGraph

Очень навскидку, под рукой линукса нет, но возможно наведет на мысли

#!/usr/bin/env bash

if [ -z "$1" ]; then
    echo "Укажите файл для обработки в качестве параметра!"
    exit 1
fi

function asksure() {
    while read -r -n 1 -p "Редактировать строку (y/n)? " -s answer
    do
        if [[ $answer = [YyNnДдНн] ]]
        then
            [[ $answer = [YyДд] ]] && retval=0
            [[ $answer = [NnНн] ]] && retval=1
            break
        fi
    done

    return $retval
}

IFS=$'\n' read -d '' -r -a ROWS < "$1"

for ROW in "${ROWS[@]}"; do
    echo "$ROW"
    if asksure; then
        read -r -p "Введите новую строку: " replace
        echo "${ROW//*/$replace}" >> tmp.file
    else
        echo "$ROW" >> tmp.file
    fi
done

mv tmp.file "$1"

Уверен, что можно обойтись и без временного файла. И, нужно решить проблему, что он убирает пустые строки. Дело за малым. :D

hanharr ()
Последнее исправление: hanharr (всего исправлений: 1)
Ответ на: комментарий от SerGraph

Без файла у меня в голове рождается какая-то рекурсия. Т.е. мы считали содержимое файла построчно в массив и крутим его в цикле. Когда мы видим нужную нам строку, то мы говорим, что хотим редактировать её, после этого нам нужно крутануть файл в цикле что-ли и уже внутри него заменить строку в файле. Или я мудрю. Если решите проблему, то напишите как)

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