Quel est le moyen le plus simple de rechercher et de remplacer une chaîne d'entrée donnée, par exemple, abc
name__, et de la remplacer par une autre chaîne, par exemple, XYZ
dans le fichier /tmp/file.txt
?
J'écris une application et j'utilise IronPython pour exécuter des commandes via SSH - mais je ne connais pas très bien Unix et je ne sais pas quoi rechercher.
J'ai entendu dire que Bash, en plus d'être une interface de ligne de commande, peut être un langage de script très puissant. Donc, si cela est vrai, je suppose que vous pouvez effectuer des actions comme celles-ci.
Puis-je le faire avec bash, et quel est le script le plus simple (une ligne) pour atteindre mon objectif?
Le moyen le plus simple consiste à utiliser sed (ou Perl):
sed -i -e 's/abc/XYZ/g' /tmp/file.txt
Qui invitera sed à effectuer une modification sur place en raison de l'option -i
. Cela peut être appelé à partir de bash.
Si vous voulez vraiment utiliser juste bash, alors ce qui suit peut marcher:
while read a ; do echo ${a//abc/XYZ} ; done < /tmp/file.txt > /tmp/file.txt.t ; mv /tmp/file.txt{.t,}
Cela boucle sur chaque ligne, en effectuant une substitution et en écrivant dans un fichier temporaire (vous ne voulez pas masquer l'entrée). Le mouvement à la fin ne fait que déplacer temporairement le nom d'origine.
La manipulation de fichier n’est normalement pas effectuée par Bash, mais par des programmes appelés par Bash, par exemple:
> Perl -pi -e 's/abc/XYZ/g' /tmp/file.txt
L’indicateur -i
lui indique de procéder à un remplacement sur place.
Voir man perlrun
pour plus de détails, y compris comment faire une sauvegarde du fichier original.
J'ai été surpris parce que je suis tombé sur cela ...
Il y a une commande "replace" qui est livrée avec le paquet "mysql-server", donc si vous l'avez installé, essayez-le:
# 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"
Voir man replace pour plus d'informations à ce sujet ...
Ceci est un vieux post mais pour ceux qui veulent utiliser des variables comme @centurian, les guillemets simples signifient que rien ne sera développé.
Un moyen simple d’obtenir des variables est de faire la concaténation de chaînes puisque cela se fait par juxtaposition en bash, les opérations suivantes devraient fonctionner:
sed -i -e 's/'"$var1"'/'"$var2"'/g' /tmp/file.txt
Bash, comme d’autres shells, n’est qu’un outil de coordination d’autres commandes. En règle générale, vous essayez d'utiliser des commandes UNIX standard, mais vous pouvez bien sûr utiliser Bash pour appeler n'importe quoi, y compris vos propres programmes compilés, d'autres scripts Shell, les scripts Python et Perl, etc.
Dans ce cas, il y a deux façons de le faire.
Si vous voulez lire un fichier et l'écrire dans un autre fichier, effectuez une recherche/remplacement au fur et à mesure, utilisez sed:
sed 's/abc/XYZ/g' <infile >outfile
Si vous souhaitez modifier le fichier à la place (comme si vous ouvriez le fichier dans un éditeur, puis le sauvegardiez), fournissez des instructions à l'éditeur de lignes 'ex'.
echo "%s/abc/XYZ/g
w
q
" | ex file
Ex est comme vi sans le mode plein écran. Vous pouvez lui donner les mêmes commandes que chez vi '': 'Invite.
J'ai trouvé ce fil parmi d'autres et je conviens qu'il contient les réponses les plus complètes. J'ajoute donc le mien aussi:
1) sed et ed sont si utiles ... à la main !!! Regardez ce code de @Johnny:
sed -i -e 's/abc/XYZ/g' /tmp/file.txt
2) lorsque ma restriction est de l’utiliser par un script Shell, aucune variable ne peut être utilisée à la place de abc ou XYZ! This semble être d'accord avec ce que je comprends au moins. Donc, je ne peux pas utiliser:
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
mais que pouvons-nous faire? Comme l'a dit @Johnny, utilisez le mot "tant que vous lisez ...", mais malheureusement, ce n'est pas la fin de l'histoire. Ce qui suit a bien fonctionné avec moi:
#edit user's 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's virtual domain to Apache 2 domain directory
......
3) Comme on peut voir si nullglob est défini alors, il se comporte étrangement quand il y a une chaîne contenant un * comme dans
<VirtualHost *:80>
ServerName www.example.com
qui devient
<VirtualHost ServerName www.example.com
il n'y a pas de cornière d'extrémité et Apache2 ne peut même pas charger
4) Ce type d'analyse devrait être plus lent que la recherche en une frappe et son remplacement, mais, comme vous l'avez déjà vu, il y a 4 variables pour 4 modèles de recherche différents élaborés à partir d'un seul cycle d'analyse!
La solution la plus appropriée à laquelle je puisse penser avec les hypothèses données du problème.
Vous pouvez utiliser sed
sed -i 's/abc/XYZ/gi' /tmp/file.txt
Utilisez -i
pour ignore case si vous n'êtes pas sûr que le texte à rechercher est abc
ou ABC
ou AbC
, etc.
Vous pouvez utiliser find
et sed
si vous ne connaissez pas votre nom de fichier:
find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;
Rechercher et remplacer dans tous les fichiers python:
find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;
Vous pouvez également utiliser la commande ed pour effectuer une recherche dans le fichier et la remplacer:
# delete all lines matching foobar
ed -s test.txt <<< $'g/foobar/d\nw'
Voir plus sur site bash-hackers
Faites attention si vous remplacez les URL par le caractère "/".
Un exemple de la façon de le faire:
sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"
Extrait de: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html
Si le fichier sur lequel vous travaillez n'est pas si volumineux et que le stocker temporairement dans une variable ne pose aucun problème, vous pouvez utiliser la substitution de chaîne Bash en une fois pour tout le fichier - vous n'avez pas besoin de la parcourir ligne par ligne:
file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt
Le contenu du fichier entier sera traité comme une longue chaîne, incluant les sauts de ligne.
XYZ peut être une variable, par exemple $replacement
, et l'un des avantages de ne pas utiliser sed est que vous n'avez pas à craindre que la chaîne de recherche ou de remplacement puisse contenir le caractère délimiteur du modèle sed (généralement, mais pas nécessairement, /). Un inconvénient est de ne pas pouvoir utiliser les expressions régulières ou les opérations plus sophistiquées de sed.
Essayez la commande Shell suivante:
find ./ -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'
Pour éditer du texte dans le fichier de manière non interactive, vous avez besoin d'un éditeur de texte sur place tel que vim.
Voici un exemple simple d'utilisation depuis la ligne de commande:
vim -esnc '%s/foo/bar/g|:wq' file.txt
Ceci est équivalent à @ réponse mince de ex éditeur qui est fondamentalement la même chose.
Voici quelques exemples pratiques ex
name__.
Remplacer le texte foo
par bar
dans le fichier:
ex -s +%s/foo/bar/ge -cwq file.txt
Suppression des espaces finaux pour plusieurs fichiers:
ex +'bufdo!%s/\s\+$//e' -cxa *.txt
Dépannage (lorsque le terminal est bloqué):
-V1
param pour afficher les messages détaillés.-cwq!
.Voir également:
Vous pouvez également utiliser python dans le script bash. Je n'ai pas eu beaucoup de succès avec certaines des meilleures réponses ici, et j'ai trouvé que cela fonctionnait sans avoir besoin de boucles:
#!/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()
Vous pouvez utiliser la commande rpl. Par exemple, vous voulez changer le nom de domaine dans tout le projet php.
rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/
Ce n’est pas clair, mais c’est très rapide et utile. :)