Найти и заменить внутри текстового файла командой Bash

Какой самый простой способ найти и заменить для данной входной строки, скажем abc, и заменить другой строкой, например XYZ в файле /tmp/file.txt?

Я пишу приложение и использую IronPython для выполнения команд через SSH — но я не очень хорошо знаю Unix и не знаю, что искать.

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

Могу ли я сделать это с помощью Bash и для чего самая простая (одна строка) script для достижения моей цели?

+461
08 февр. '09 в 11:57
источник поделиться
14 ответов

Самый простой способ - использовать sed (или perl):

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

Который вызовет sed для редактирования на месте с помощью опции -i. Это можно вызвать из bash.

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

while read a ; do echo ${a//abc/XYZ} ; done < /tmp/file.txt > /tmp/file.txt.t ; mv /tmp/file.txt{.t,}

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

+778
08 февр. '09 в 12:20
источник

Связанные вопросы


Похожие вопросы

Обработка файлов обычно не выполняется с помощью Bash, а с помощью программ, вызываемых Bash, например:

> perl -pi -e 's/abc/XYZ/g' /tmp/file.txt

Флаг -i указывает, что он выполняет замену на месте.

Подробнее см. man perlrun, в том числе, как сделать резервную копию исходного файла.

+155
08 февр. '09 в 12:10
источник

Я был удивлен, потому что я наткнулся на это...

Существует команда "replace" , которая поставляется с пакетом "mysql-server" , поэтому, если вы его установили, попробуйте:

# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt

# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"

См. man replace для получения дополнительной информации об этом...

+63
09 апр. '13 в 15:35
источник

Это старый пост, но для тех, кто хочет использовать переменные, поскольку @centurian сказал, что одиночные кавычки означают, что ничего не будет расширено.

Простым способом получения переменных является выполнение конкатенации строк, поскольку это выполняется путем сопоставления в bash, следующее должно работать:

sed -i -e 's/'"$var1"'/'"$var2"'/g' /tmp/file.txt

+38
07 дек. '15 в 12:48
источник

Bash, как и другие оболочки, является всего лишь инструментом для координации других команд. Обычно вы пытаетесь использовать стандартные команды UNIX, но вы можете, конечно, использовать Bash для вызова чего-либо, включая ваши собственные скомпилированные программы, другие сценарии оболочки, скрипты Python и Perl и т.д.

В этом случае есть несколько способов сделать это.

Если вы хотите прочитать файл и записать его в другой файл, выполнив поиск/замену по ходу, используйте sed:

sed 's/abc/XYZ/g' <infile >outfile

Если вы хотите отредактировать файл на месте (как бы открыв файл в редакторе, отредактировав его, а затем сохраните), подайте инструкции редактору строк "ex"

echo "%s/abc/XYZ/g
w
q
" | ex file

Ex похож на vi без полноэкранного режима. Вы можете дать ему те же команды, что и в vi ':'.

+37
08 февр. '09 в 12:13
источник

Нашел эту тему среди других, и я согласен, что она содержит наиболее полные ответы, поэтому я тоже добавляю:

1) sed и ed настолько полезны... вручную! Посмотрите на этот код от @Johnny:

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

2), когда мое ограничение заключается в том, чтобы использовать его оболочкой script, тогда вместо abc или XYZ никакая переменная не может использоваться! Это, похоже, согласуется с тем, что я понимаю по крайней мере. Поэтому я не могу использовать:

x='abc'
y='XYZ'
sed -i -e 's/$x/$y/g' /tmp/file.txt
#or,
sed -i -e "s/$x/$y/g" /tmp/file.txt

но что мы можем сделать? Как сказал @Johnny, используйте "во время чтения...", но, к сожалению, это не конец истории. Следующее хорошо со мной работало:

#edit user virtual domain
result=
#if nullglob is set then, unset it temporarily
is_nullglob=$( shopt -s | egrep -i '*nullglob' )
if [[ is_nullglob ]]; then
   shopt -u nullglob
fi
while IFS= read -r line; do
   line="${line//'<servername>'/$server}"
   line="${line//'<serveralias>'/$alias}"
   line="${line//'<user>'/$user}"
   line="${line//'<group>'/$group}"
   result="$result""$line"'\n'
done < $tmp
echo -e $result > $tmp
#if nullglob was set then, re-enable it
if [[ is_nullglob ]]; then
   shopt -s nullglob
fi
#move user virtual domain to Apache 2 domain directory
......

3) Как можно видеть, установлен ли nullglob, он ведет себя странно, когда есть строка, содержащая *, как в

<VirtualHost *:80>
 ServerName www.example.com

который становится

<VirtualHost ServerName www.example.com

нет конечной угловой скобки и Apache2 не может даже загружаться!

4) Этот вид разбора должен быть медленнее, чем поиск и замена одним нажатием, но, как вы уже видели, есть 4 переменные для 4 разных шаблонов поиска, которые работают только в одном цикле разбора!

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

+32
07 февр. '13 в 14:48
источник

Вы можете использовать Sed

sed -i 's/abc/XYZ/gi' /tmp/file.txt

Используйте -i для игнорирования регистра, если вы не уверены, что текст для поиска - это abc ABC или AbC и т.д.

Вы можете использовать find и sed если у вас нет имени файла:

 find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;

Найти и заменить во всех файлах Python:

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
+18
14 янв. '17 в 9:45
источник

Вы также можете использовать команду ed для поиска в файле и заменить:

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 

Подробнее о bash -hackers site

+11
14 июн. '09 в 16:37
источник

Если файл, над которым вы работаете, не так велик, а временное его хранение в переменной не представляет проблемы, вы можете использовать замену строки Bash для всего файла сразу - нет необходимости переходить по этой строке по строке:

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt

Все содержимое файла будет рассматриваться как одна длинная строка, включая строки.

XYZ может быть переменной eg $replacement, и одно из преимуществ не использования sed здесь заключается в том, что вам не нужно беспокоиться о том, что строка поиска или замены может содержать символ разделителя шаблона sed (обычно, но необязательно, /), Недостатком является невозможность использования регулярных выражений или любых более сложных операций.

+7
15 апр. '17 в 2:09
источник

Будьте осторожны, если вы замените URL-адресом символом "/".

Пример того, как это сделать:

sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"

Извлечено из: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html

+7
27 июл. '15 в 19:08
источник

Чтобы редактировать текст в файле неинтерактивно, вам нужен текстовый редактор на месте, например, vim.

Вот простой пример, как использовать его из командной строки:

vim -esnc '%s/foo/bar/g|:wq' file.txt

Это эквивалентно ответу @slim бывшего редактора, что в основном то же самое.

Вот несколько ex практических примеров.

Замена текста foo на bar в файле:

ex -s +%s/foo/bar/ge -cwq file.txt

Удаление конечных пробелов для нескольких файлов:

ex +'bufdo!%s/\s\+$//e' -cxa *.txt

Устранение неисправностей (когда терминал застрял):

  • Добавьте параметр -V1 для отображения подробных сообщений.
  • Принудительное -cwq!: -cwq! ,

Смотрите также:

+4
11 мая '15 в 20:21
источник

Попробуйте следующую команду оболочки:

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
+4
31 мая '16 в 23:55
источник

Вы также можете использовать python в bash script. Я не имел большого успеха с некоторыми из лучших ответов здесь, и нашел, что это работает без необходимости в циклах:

#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'

s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()
+2
03 мая '16 в 18:44
источник

Вы можете использовать команду rpl. Например, вы хотите изменить доменное имя во всем проекте php.

rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/  

Это не ясно bash причины, но это очень быстро и полезно.:)

+1
12 февр. '15 в 8:34
источник

Посмотрите другие вопросы по меткам или Задайте вопрос