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

16

Как мы все знаем, sedявляется очень эффективным , чтобы найти и заменить строку, например , находка «а» и заменить его на «Ъ»: sed 's/a/b/g'.

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

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

binghenzq
источник
На самом деле, это просто замена на основе регулярных выражений. Любой инструмент или язык , способный обрабатывать такие вещи будут иметь возможность делать то же самое, но с различным синтаксисом: $var=~s/a/b/g, gsub(/a/,"b",var), var.gsub(/a/,'b'), var.replace(/a/g,'b'), preg_replace("/a/","b",$var), regsub -all a b $var. Кроме того, многие инструменты и языки могут также выполнять замену строк в виде простого текста. Так что ваш вопрос как-то широк.
manatwork
1
Почему? Какую проблему ты пытаешься решить?
Жиль "ТАК - перестать быть злым"
Обрезанные системы Linux для телевидения не имеют команды sed. Поэтому я должен использовать другую команду или скрипт вместо sed 's / a / b / g'.
Binghenzq

Ответы:

12

Да, есть множество способов сделать это. Вы можете использовать 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 -pie "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и записывается обратно в то же имя файла, которое мы только что удалили, эффективно заменяя его.

SLM
источник
Спасибо за ваш ответ, и я попробую его на следующий рабочий день. Но я не уверен, что это сработает, потому что в обрезанных системах Linux, таких как «sed», может не существовать какая-то команда, так что я все еще хочу использовать команду «find» , 'grep' и так далее, чтобы решить это.
Binghenzq
@binghenzq - я добавил примеры, которые встраивают редактирование файла.
SLM
-1 Я редко понижаю голос, но в этом случае вопрос кажется более простым, нежели другим, более / менее сложным и, вероятно, также зависимым. Если бы вопрос был только об альтернативах для полной установки * nix-машины, то я бы, вероятно, +1 это хороший ответ.
Майкл Даррант
@MichaelDurrant - я только что добавил эти сложные встроенные правки, потому что ОП попросил их. Также ОП установил требование НЕ использовать sedне I. Сед является подходящим инструментом для таких замен, и он, очевидно, просит лучше понять роль этих инструментов, поэтому показывать кому-то эти вещи, хотя они и плохие, чрезвычайно полезны для показа их почему. Слишком много раз люди, находящиеся в курсе, просто говорят «не делай этого», не объясняя, почему, и я тоже. Но спасибо, по крайней мере, оставить комментарий о том, почему вы DV.
slm
Конечно, я думал, что это был отличный ответ во всех других отношениях. да я ненавижу -1 без объяснения причин.
Майкл Даррант
13

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

$ echo "foobar" | tr a b   
foobbr

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

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

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

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

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

Тердон
источник
Есть ли возможность игнорировать регистр в ${foo//a/b}?
Алик Эльзин-килака
@ AlikElzin-kilaka Боюсь, что нет. Вы должны будете использовать что - то более сложное , как, например: echo "$foo" | sed 's/a/b/iили дать класс символов: echo ${foo//[aA]/b}.
Тердон
4

Вы можете использовать Vim в режиме Ex:

ex -s -c '%s/a/b/g|x' file
  1. % выбрать все строки

  2. s замена

  3. g глобальная замена

  4. x сохранить и закрыть

Стивен Пенни
источник
большое спасибо. просто добавьте, флаг -c - это выполнение команды в начале редактирования (поскольку ex - редактор), а флаг -s - это либо режим сценария, отключающий обратную связь, либо, как некоторые любят говорить, режим слиента. Ссылка
Джимми М.Г. Лим
3

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

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

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

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

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

evilsoup
источник
2

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

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

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

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

ed -s file <<!
,s/a/b/g
w
q
!
Жиль Квено
источник