Какой самый простой способ найти и заменить для данной входной строки, скажем abc
, и заменить другой строкой, например XYZ
в файле /tmp/file.txt
?
Я пишу приложение и использую IronPython для выполнения команд через SSH — но я не очень хорошо знаю Unix и не знаю, что искать.
Я слышал, что Bash, помимо интерфейса командной строки, может быть очень мощным языком сценариев. Итак, если это так, я предполагаю, что вы можете выполнять такие действия.
Могу ли я сделать это с помощью Bash и для чего самая простая (одна строка) script для достижения моей цели?
Самый простой способ - использовать 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,}
Это циклически перемещается по каждой строке, выполняет подстановку и записывается во временный файл (не нужно забивать ввод). Перемещение в конце просто временно перемещается к исходному имени.
Обработка файлов обычно не выполняется с помощью Bash, а с помощью программ, вызываемых Bash, например:
> perl -pi -e 's/abc/XYZ/g' /tmp/file.txt
Флаг -i
указывает, что он выполняет замену на месте.
Подробнее см. man perlrun
, в том числе, как сделать резервную копию исходного файла.
perl -pi -e 's/chdir (?:\\/[\\w\\.\\-]+)+/chdir blah/g' text
, но я получаю сообщение об ошибке из-за отсутствия пробела между шаблон и следующее слово не рекомендуется в строке -e 1. Не соответствует (в регулярном выражении; отмечен знаком <- HERE в m / (chdir) () (<- HERE?: \\ / at -e line 1.
Я был удивлен, потому что я наткнулся на это...
Существует команда "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 для получения дополнительной информации об этом...
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 ':'.
Нашел эту тему среди других, и я согласен, что она содержит наиболее полные ответы, поэтому я тоже добавляю:
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 разных шаблонов поиска, которые работают только в одном цикле разбора!
Наиболее подходящее решение, о котором я могу думать, с данными предположениями проблемы.
sed -e "s/$x/$y/"
, и это сработает. Не двойные кавычки. Это может серьезно сбить с толку, если строки в самих переменных содержат символы со специальным значением. Например, если x = "/" или x = "\". Когда вы сталкиваетесь с этими проблемами, это, вероятно, означает, что вы должны прекратить попытки использовать оболочку для этой работы.
Это старый пост, но для тех, кто хочет использовать переменные, поскольку @centurian сказал, что одиночные кавычки означают, что ничего не будет расширено.
Простым способом получения переменных является выполнение конкатенации строк, поскольку это выполняется путем сопоставления в bash, следующее должно работать:
sed -i -e 's/'"$var1"'/'"$var2"'/g' /tmp/file.txt
Вы также можете использовать команду ed для поиска в файле и заменить:
# delete all lines matching foobar
ed -s test.txt <<< $'g/foobar/d\nw'
Подробнее о bash -hackers site
sed -i <pattern> <filename>
). Очень хорошо!
Вы можете использовать sed
sed -i 's/abc/XYZ/gi' /tmp/file.txt
Используйте я для случая игнорирования, если вы не уверены, что текст для поиска - 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' {} \;
Будьте осторожны, если вы замените 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
find./-type f -name "file *.txt" | xargs sed -i -e 's/abc/xyz/g'
Чтобы редактировать текст в файле неинтерактивно, вам нужен текстовый редактор на месте, такой как vim.
Вот простой пример, как использовать его из командной строки:
vim -esnc '%s/foo/bar/g|:wq' file.txt
Это эквивалентно @slim answer редактора ex, который в основном то же самое.
Вот несколько практических примеров ex
.
Замена текста foo
на bar
в файле:
ex -s +%s/foo/bar/ge -cwq file.txt
Удаление конечных пробелов для нескольких файлов:
ex +'bufdo!%s/\s\+$//e' -cxa *.txt
См. также:
Если файл, над которым вы работаете, не так велик, а временное его хранение в переменной не представляет проблемы, вы можете использовать замену строки Bash для всего файла сразу - нет необходимости переходить по этой строке по строке:
file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
Все содержимое файла будет рассматриваться как одна длинная строка, включая строки.
XYZ может быть переменной eg $replacement
, и одно из преимуществ не использования sed здесь заключается в том, что вам не нужно беспокоиться о том, что строка поиска или замены может содержать символ разделителя шаблона sed (обычно, но необязательно, /), Недостатком является невозможность использования регулярных выражений или любых более сложных операций.
Вы также можете использовать 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()
Вы можете использовать команду rpl. Например, вы хотите изменить доменное имя во всем проекте php.
rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/
Это не ясно bash причины, но это очень быстро и полезно.:)
-i -e