Найти и заменить внутри текстового файла командой Bash
Какой самый простой способ найти и заменить для данной входной строки, скажем abc
, и заменить другой строкой, например XYZ
в файле /tmp/file.txt
?
Я пишу приложение и использую IronPython для выполнения команд через SSH — но я не очень хорошо знаю Unix и не знаю, что искать.
Я слышал, что Bash, помимо интерфейса командной строки, может быть очень мощным языком сценариев. Итак, если это так, я предполагаю, что вы можете выполнять такие действия.
Могу ли я сделать это с помощью Bash и для чего самая простая (одна строка) script для достижения моей цели?
Ответы
Ответ 1
Самый простой способ - использовать 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,}
Это циклически повторяет каждую строку, делая подстановку и записывая во временный файл (не хочу, чтобы ввод был заглушен). Движение в конце просто временно перемещается к исходному имени.
Ответ 2
Обработка файлов обычно выполняется не Bash, а программами, вызываемыми Bash, например:
perl -pi -e 's/abc/XYZ/g' /tmp/file.txt
Флаг -i
говорит ему сделать замену на месте.
См. man perlrun
для получения более подробной информации, в том числе о том, как сделать резервную копию исходного файла.
Ответ 3
Я был удивлен, потому что я наткнулся на это...
Существует команда "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 для получения дополнительной информации об этом...
Ответ 4
Это старый пост, но для тех, кто хочет использовать переменные, как @centurian сказал, что одинарные кавычки означают, что ничего не будет расширено.
Простой способ получить переменные - это выполнить конкатенацию строк, так как это делается с помощью сопоставления в bash: должно работать следующее:
sed -i -e "s/$var1/$var2/g" /tmp/file.txt
Ответ 5
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 ':'.
Ответ 6
Нашел эту тему среди других, и я согласен, что она содержит наиболее полные ответы, поэтому я тоже добавляю:
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 разных шаблонов поиска, которые работают только в одном цикле разбора!
Наиболее подходящее решение, о котором я могу думать, с данными предположениями проблемы.
Ответ 7
Вы можете использовать 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' {} \;
Ответ 8
Вы также можете использовать команду ed для поиска в файле и заменить:
# delete all lines matching foobar
ed -s test.txt <<< $'g/foobar/d\nw'
Подробнее о bash -hackers site
Ответ 9
Будьте осторожны, если вы замените 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
Ответ 10
Если файл, над которым вы работаете, не так велик, а временное его хранение в переменной не представляет проблемы, вы можете использовать замену строки Bash для всего файла сразу - нет необходимости переходить по этой строке по строке:
file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
Все содержимое файла будет рассматриваться как одна длинная строка, включая строки.
XYZ может быть переменной eg $replacement
, и одно из преимуществ не использования sed здесь заключается в том, что вам не нужно беспокоиться о том, что строка поиска или замены может содержать символ разделителя шаблона sed (обычно, но необязательно, /), Недостатком является невозможность использования регулярных выражений или любых более сложных операций.
Ответ 11
Чтобы редактировать текст в файле неинтерактивно, вам нужен текстовый редактор на месте, например, 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!
,
Смотрите также:
Ответ 12
Попробуйте следующую команду оболочки:
find ./ -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
Ответ 13
Вы также можете использовать 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()
Ответ 14
Вы можете использовать команду rpl. Например, вы хотите изменить доменное имя во всем проекте php.
rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/
Это не ясно bash причины, но это очень быстро и полезно.:)