Как найти и заменить строку без использования команды Sed?

Вопрос или проблема

Как мы все знаем, sed очень эффективен для поиска и замены строк, например, найти ‘a’ и заменить на ‘b’: sed 's/a/b/g'.

Можно ли сделать это с помощью других команд или скриптов оболочки вместо sed?

Это для ограниченных систем Linux для телевизоров, на которых отсутствует команда sed. Поэтому мне нужно использовать другие команды или скрипты вместо sed 's/a/b/g'.

Классической альтернативой для замены одиночных букв является команда tr, которая должна быть доступна на любой системе:

$ echo "foobar" | tr a b   
foobbr

tr на самом деле лучше, чем sed, для этой задачи, поскольку использование sed (не говоря уже о perl или awk) для замены одиночных букв похоже на то, как использовать кувалду для того, чтобы убить муху.

grep не предназначен для этого, он не изменяет свой вход, а лишь ищет в нем.

В качестве альтернативы, вы можете использовать возможности замены некоторых оболочек. Вот как это выглядит с использованием синтаксиса ksh, zsh или bash:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

Мы могли бы дать вам более конкретные ответы, если бы вы объяснили, какую именно проблему вы пытаетесь решить.

Да, есть множество способов сделать это. Вы также можете использовать awk, perl или bash для выполнения этих действий. В общем, однако, sed вероятно является наиболее подходящим инструментом для выполнения таких задач.

Примеры

Скажем, у меня есть эти образцы данных в файле data.txt:

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Perl

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Редактирование на месте

Приведенные выше примеры также могут напрямую изменять файлы. Пример с Perl тривиален. Просто добавьте переключатель -i.

$ perl -pi -e "s/foo/foofoofoo/g" data.txt 

Для awk это немного менее прямолинейно, но столь же эффективно:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

Этот метод создает подпроцесс с фигурными скобками ‘{ … }`, где файл перенаправляется в него следующим образом:

$ { ... } < data.txt

После того как файл был перенаправлен в подпроцесс, он удаляется, а затем awk выполняется над содержимым файла, которое было прочитано в STDIN подпроцесса. Это содержимое затем обрабатывается awk и записывается обратно в тот же файл с именем, который мы только что удалили, тем самым заменяя его.

Вы можете использовать инструмент POSIX ex:

ex a.txt <<eof
%s/Sunday/Monday/g
xit
eof

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html

Если вы работаете с файлом, а не с потоком, вы можете использовать стандартный текстовый редактор ed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

Это должно быть доступно на любом *nix. Запятая в ',s/a/b/g' указывает ed работать на каждой строке (вы также можете использовать %, что будет более привычно, если вы привыкли к vim), а остальная часть — это стандартный поиск и замена. w говорит ему записать (сохранить) файл, q говорит ему выйти.

Обратите внимание, что в отличие от параметра -i в sed (и аналогичных параметров в других инструментах), это действительно редактирует файл на месте, а не использует временные файлы.

Я не думаю, что это возможно сделать с потоками, но я также не знаю много о ed, и меня не удивит, если у него действительно есть такая возможность (походя на философию Unix).

Используя команду предка (где -s означает тихий (беззвучный), а запятая перед командами означает выполнение на всех строках):

Просто печатаем на STDOUT:

ed -s file <<!
,s/a/b/g
,p
q
!

замена на месте:

ed -s file <<!
,s/a/b/g
w
q
!

Если вы используете операционную систему Linux, например, Ubuntu Desktop, как я, у вас будет установлен python.

С помощью Python мы можем выполнять замену текста следующим образом:

result=$(python << EOT
s="$your_string_in_shell_script"
r = s.replace('text to replace', 'replaced by this text')
print(r)
EOT)

echo $result

Если у вас есть Python, вы можете проходить по дереву папок и заменять что угодно, не углубляясь в регулярные выражения. Найти и заменить на месте:

PYTHON_CODE=$(cat <<PY_END
##################
import os
f_path = "./"
patch_pairs=[ ('AAA', 'BBB') ] # AAA -> BBB
patch_pairs=patch_pairs+[ ('"CCC"', '"DDD"') ] # "CCC" -> "DDD"
# и т.д...
patch_exts= [".py"]
for r, d, f in os.walk(f_path):
    for file_name in f:
        for ext in patch_exts:
            if file_name.endswith(ext):
                fpath = os.path.join(r, file_name)
                fpath = os.path.abspath(fpath)
                try:
                    anychange = 0
                    with open(fpath, "r+") as text_file:
                        texts = text_file.read()
                        for pp in patch_pairs:
                            if pp[0] in texts:
                                anychange = anychange+1
                                texts = texts.replace(pp[0], pp[1])
                    if anychange>0:
                        with open(fpath, "w") as text_file:
                            text_file.write(texts)
                            print("// патч",fpath)
                except Exception as e:
                    print("// не удалось отредактировать файл, пропуск", fpath, e)

##################
PY_END
)
python -c "$PYTHON_CODE"

Ответ или решение

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

1. Использование команды tr

Если необходимо заменить одиночные символы, можно воспользоваться командой tr, которая доступна практически на всех операционных системах Linux:

echo "foobar" | tr 'a' 'b'
# Вывод: foobbr

2. Подстановка в оболочке (bash, ksh, zsh)

Современные оболочки, такие как bash, поддерживают встроенные возможности подстановки, что позволяет делать замену напрямую в переменной:

foo="foobar"
echo "${foo//a/b}"
# Вывод: foobbr

3. Использование awk

Для более сложных замен в текстовых файлах можно использовать awk, который отлично подходит для обработки текстовых потоков:

awk '{gsub("foo", "foofoofoo", $0); print}' data.txt

Этот пример заменяет все вхождения foo на foofoofoo в файле data.txt.

4. Использование perl

Perl также является мощным инструментом для выполнения замен:

perl -pe "s/foo/foofoofoo/g" data.txt

Для редактирования файла на месте, добавьте опцию -i:

perl -pi -e "s/foo/foofoofoo/g" data.txt

5. Использование текстового редактора ed

Если вы работаете с файлами, можно применить традиционный текстовый редактор ed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

Здесь запятая означает, что замена будет выполнена на каждой строке файла. Команды w и q сохраняют изменения и выходят из редактора, соответственно.

6. Использование ex

Также можно воспользоваться текстовым редактором ex, чтобы сделать замену:

ex data.txt <<eof
%s/Sunday/Monday/g
xit
eof

7. Python

Если на системе установлен Python, можно выполнить замену текста с помощью следующего кода:

result=$(python <<EOT
s = "$your_string_in_shell_script"
r = s.replace('text to replace', 'replaced by this text')
print(r)
EOT)

echo $result

Для включения замены в нескольких файлах в директории, можно использовать следующий скрипт Python:

import os

patch_pairs = [('AAA', 'BBB'), ('"CCC"', '"DDD"')]  # Пары для замены
patch_exts = ['.py']  # Принимаемые расширения файлов

for r, d, f in os.walk('./'):
    for file_name in f:
        for ext in patch_exts:
            if file_name.endswith(ext):
                fpath = os.path.join(r, file_name)
                with open(fpath, "r") as text_file:
                    texts = text_file.read()
                    for old, new in patch_pairs:
                        texts = texts.replace(old, new)
                with open(fpath, "w") as text_file:
                    text_file.write(texts)

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...