Réponses:
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
Les occurrences de "foo" seront remplacées par "bar".
Sur les systèmes BSD comme macOS, vous devez fournir une extension de sauvegarde comme -i '.bak'
ou bien "risque de corruption ou de contenu partiel" selon la page de manuel.
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *
sed
, -i
nécessite une chaîne après, qui est ajoutée aux anciens noms de fichiers. sed -i .bak 's/foo/bar/g' *.xx
Déplace donc tous les .xx
fichiers vers le .xx.bak
nom équivalent , puis génère les .xx
fichiers avec la substitution foo → bar.
sed -i 's/foo\ with\ spaces/bar/g' *
. Je suppose que vous l'avez découvert après si longtemps ... mais de cette façon, cela reste pour d'autres qui trouvent le même problème.
sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
Similaire à la réponse de Kaspar mais avec le drapeau g pour remplacer toutes les occurrences sur une ligne.
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
Pour la casse globale insensible:
find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
LC_ALL=C find ./ -type f -exec sed -i '' -e 's/proc.priv/priv/g' {} \;
(voir cet article et celui-ci )
--include=*.whatever
avec -r
.git/
. Assurez-vous de cd
descendre à un niveau inférieur.
git status
retourne: error: bad index file sha1 signature.... fatal: index file corrupt
. Ce qui donne?
La réponse de @ kev est bonne, mais n'affecte que les fichiers du répertoire immédiat. L'exemple ci-dessous utilise grep pour rechercher récursivement des fichiers. Cela fonctionne pour moi à chaque fois.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
Répartition des commandes
grep -r : --recursive , lit récursivement tous les fichiers de chaque répertoire.
grep -l : --print-with-matches , imprime le nom de chaque fichier qui a une correspondance, au lieu d'imprimer les lignes correspondantes.
grep -i : --ignore-case .
xargs : transformez le STDIN en arguments, suivez cette réponse .
La commande xargs -i @ ~ contient @ ~ : un espace réservé pour l'argument à utiliser à une position spécifique dans la commande ~ ~ , le signe @ est un espace réservé qui pourrait être remplacé par n'importe quelle chaîne.
sed -i : éditez les fichiers sur place, sans sauvegardes.
sed s / regexp / remplacement / : chaîne de remplacement correspondant à regexp avec remplacement .
sed s / regexp / remplacement / g : global , faites la substitution pour chaque correspondance au lieu de seulement la première correspondance.
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
|
, aussi, pourquoi -i
dans la commande xargs? J'ai lu dans le manuel qu'il est obsolète et devrait être utilisé à la -I
place. Et est @
utilisé comme délimiteur pour le début et la fin du motif?
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
rli
) et le @
signe par exemple
Cela a fonctionné pour moi:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Howerver, cela n'a pas: sed -i 's/string1/string2/g' *
. Peut-être que "foo" n'était pas censé être string1 et "bar" pas string2.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Il y a quelques réponses standard à cela déjà listées. En règle générale, vous pouvez utiliser find pour répertorier récursivement les fichiers, puis effectuer les opérations avec sed ou perl .
Pour la plupart des utilisations rapides, vous pouvez trouver que la commande rpl est beaucoup plus facile à retenir. Voici le remplacement (foo -> bar), récursivement sur tous les fichiers:
rpl -R foo bar .
Vous devrez probablement l'installer ( apt-get install rpl
ou similaire).
Cependant, pour les tâches plus difficiles qui impliquent des expressions régulières et une substitution arrière, ou des renommages de fichiers ainsi que la recherche et le remplacement, l'outil le plus général et le plus puissant que je connaisse est repren , un petit script Python que j'ai écrit il y a quelque temps pour certains tâches de renommage et de refactoring plus épineuses. Les raisons pour lesquelles vous pourriez préférer ce sont:
Pour l' utiliser, pip install repren
. Consultez le README pour des exemples.
Pour remplacer une chaîne dans plusieurs fichiers, vous pouvez utiliser:
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
Par exemple
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Pour remplacer un chemin dans les fichiers (en évitant les caractères d'échappement), vous pouvez utiliser la commande suivante:
sed -i 's@old_path@new_path@g'
Le signe @ signifie que tous les caractères spéciaux doivent être ignorés dans une chaîne suivante.
Si votre chaîne contient une barre oblique (/), vous pouvez remplacer le délimiteur par '+'.
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Cette commande s'exécuterait récursivement dans le répertoire en cours.
../domain.com
àdomain.com
Les occurrences de la première ligne de "foo" seront remplacées par "bar". Et vous pouvez utiliser la deuxième ligne pour vérifier.
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
Si vous avez une liste de fichiers que vous pouvez utiliser
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
Si vous avez tous les fichiers que vous pouvez utiliser
replace "old_string" "new_string" -- *
Si vous avez une liste de fichiers avec extension, vous pouvez utiliser
replace "old_string" "new_string" -- *.extension
replace "old_string" "new_string" -- *.txt
replace
utilitaire. Sans cette information, cette réponse est incomplète.
"Vous pouvez également utiliser find et sed, mais je trouve que cette petite ligne de perl fonctionne bien.
perl -pi -w -e 's/search/replace/g;' *.php
"(Extrait de http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php )
Mes meilleurs résultats proviennent de l'utilisation de perl et grep (pour garantir que le fichier a l'expression de recherche)
perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
Étant donné que vous souhaitez rechercher la chaîne search
et la remplacer par replace
plusieurs fichiers, voici ma formule d'une ligne testée au combat :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
Explication rapide de grep:
-R
- recherche récursive-i
- insensible à la casse-I
- sauter les fichiers binaires (vous voulez du texte, non?)-l
- imprimer une liste simple en sortie. Nécessaire pour les autres commandesLa sortie grep est ensuite dirigée vers sed (via xargs) qui est utilisée pour remplacer réellement le texte. Le -i
drapeau modifie directement le fichier. Retirez-le pour une sorte de mode "marche à sec".
J'ai concocté ma propre solution avant de trouver cette question (et les réponses). J'ai cherché différentes combinaisons de "remplacer" "plusieurs" et "xml", car c'était mon application, mais je n'ai pas trouvé celle-ci en particulier.
Mon problème: j'avais des fichiers xml de printemps avec des données pour les cas de test, contenant des objets complexes. Un refactor sur le code source java a changé beaucoup de classes et ne s'est pas appliqué aux fichiers de données xml. Afin de sauvegarder les données des cas de test, j'ai dû changer tous les noms de classe dans tous les fichiers xml, répartis sur plusieurs répertoires. Tout en enregistrant des copies de sauvegarde des fichiers xml d'origine (bien que ce ne soit pas un must, car le contrôle de version me sauverait ici).
Je cherchais une combinaison de find
+ sed
, car cela a fonctionné pour moi dans d'autres situations, mais pas avec plusieurs remplacements à la fois.
Ensuite, j'ai trouvé la réponse ask ubuntu et cela m'a aidé à construire ma ligne de commande:
find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
Et cela a fonctionné parfaitement (eh bien, mon cas avait six remplacements différents). Mais veuillez noter qu'il touchera tous les fichiers * .xml dans le répertoire actuel. Pour cette raison, et si vous êtes responsable devant un système de contrôle de version, vous voudrez peut-être filtrer en premier et ne transmettre qu'à sed
ceux qui ont réellement les chaînes que vous voulez; comme:
find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
findstr /spin /c:"quéquieresbuscar" *.xml
ce sera pratique.
Vraiment boiteux, mais je n'ai pu faire fonctionner aucune des commandes sed sur OSX, j'ai donc fait cette chose stupide à la place:
:%s/foo/bar/g
:wn
^ - copiez ces trois lignes dans mon presse-papiers (oui, incluez la nouvelle ligne de fin), puis:
vi *
et maintenez la commande-v jusqu'à ce qu'il indique qu'il n'y a plus de fichiers.
Dumb ... hacky ... efficace ...
Sur un MacBook Pro, j'ai utilisé ce qui suit (inspiré de https://stackoverflow.com/a/19457213/6169225 ):
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
s'assurera que vous n'effectuez aucune sauvegarde.
-e
pour regex moderne.
-e
indique simplement à sed que le prochain jeton est une commande. Pour les expressions régulières étendues, utilisez -E
plutôt.
L'éditeur de flux modifie plusieurs fichiers «sur place» lorsqu'il est appelé avec le -i
commutateur, ce qui prend un fichier de sauvegarde se terminant en argument. Donc
sed -i.bak 's/foo/bar/g' *
remplace foo
par bar
dans tous les fichiers de ce dossier, mais ne descend pas dans les sous-dossiers. Cela va cependant générer un nouveau .bak
fichier pour chaque fichier de votre répertoire. Pour ce faire de manière récursive pour tous les fichiers de ce répertoire et tous ses sous-répertoires, vous avez besoin d'un assistant, comme find
, pour parcourir l'arborescence des répertoires.
find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *
find
vous permet des restrictions supplémentaires sur les fichiers à modifier, en spécifiant d'autres arguments comme find ./ -name '*.php' -or -name '*.html' -print0
, si nécessaire.
Remarque: GNU sed
ne nécessite pas de fin de fichier, sed -i 's/foo/bar/g' *
fonctionnera également; FreeBSD sed
demande une extension, mais permet un espace entre les deux, donc ça sed -i .bak s/foo/bar/g *
marche.
script pour la commande multiedit
multiedit [-n PATTERN] OLDSTRING NEWSTRING
D'après la réponse de Kaspar, j'ai créé un script bash pour accepter les arguments de ligne de commande et éventuellement limiter les noms de fichiers correspondant à un modèle. Enregistrez dans votre $ PATH et rendez exécutable, puis utilisez simplement la commande ci-dessus.
Voici le script:
#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n
[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"
# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then # if -n option is given:
# replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
# replace OLDSTRING with NEWSTRING recursively in all files
find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi
Si le fichier contient des barres obliques inverses (chemins généralement), vous pouvez essayer quelque chose comme ceci:
sed -i -- 's,<path1>,<path2>,g' *
ex:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Pour maintenir mon nœud anglais personnel, j'ai écrit un script utilitaire qui aide à remplacer plusieurs paires d'anciennes / nouvelles chaînes, pour tous les fichiers d'un répertoire de manière récursive.
Les multiples paires d'anciennes / nouvelles chaînes sont gérées dans une carte de hachage.
Le répertoire peut être défini via la ligne de commande ou la variable d'environnement, la carte est codée en dur dans le script, mais vous pouvez modifier le code à charger à partir d'un fichier, si nécessaire.
Il nécessite bash 4.2, en raison d'une nouvelle fonctionnalité.
en_standardize.sh:
#! /bin/bash
# (need bash 4.2+,)
#
# Standardize phonetic symbol of English.
#
# format:
# en_standardize.sh [<dir>]
#
# params:
# * dir
# target dir, optional,
# if not specified then use environment variable "$node_dir_en",
# if both not provided, then will not execute,
# *
#
paramCount=$#
# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
echo -e "dir specified (in command):\n\t$1\n"
targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
targetDir=$node_dir_en
else # environable not set,
echo "dir not specified, won't execute"
exit
fi
# check whether dir exists,
if [ -d $targetDir ]; then
cd $targetDir
else
echo -e "invalid dir location:\n\t$targetDir\n"
exit
fi
# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")
# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'
# do replace,
for key in "${!itemMap[@]}"; do
grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done
echo -e "\nDone."
exit
Utiliser la commande ack serait beaucoup plus rapide comme ceci:
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
Aussi si vous avez un espace blanc dans le résultat de la recherche. Vous devez y échapper.
Je donne un exemple pour corriger une erreur de shebang commune dans les sources python.
Vous pouvez essayer l'approche grep / sed. En voici un qui fonctionne avec GNU sed et ne cassera pas un dépôt git:
$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}
Ou vous pouvez utiliser greptile :)
$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .
Je viens de tester le premier script, et le second devrait également fonctionner. Soyez prudent avec les caractères d'échappement, je pense qu'il devrait être plus facile d'utiliser greptile dans la plupart des cas. Bien sûr, vous pouvez faire beaucoup de choses intéressantes avec sed, et pour cela il peut être préférable de maîtriser son utilisation avec xargs.
J'ai trouvé celui-ci dans un autre article (je ne me souviens pas lequel) et bien qu'il ne soit pas le plus élégant, il est simple et en tant qu'utilisateur Linux novice, cela ne m'a posé aucun problème
for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done
si vous avez des espaces ou d'autres caractères spéciaux, utilisez un \
for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
pour les chaînes dans les sous-répertoires, utilisez **
for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
Il existe un moyen plus simple d'utiliser un simple fichier de script:
# sudo chmod +x /bin/replace_string_files_present_dir
ouvrez le fichier dans gedit ou un éditeur de votre choix, j'utilise ici gedit.
# sudo gedit /bin/replace_string_files_present_dir
Ensuite, dans l'éditeur, collez ce qui suit dans le fichier
#!/bin/bash
replace "oldstring" "newstring" -- *
replace "oldstring1" "newstring2" -- *
#add as many lines of replace as there are your strings to be replaced for
#example here i have two sets of strings to replace which are oldstring and
#oldstring1 so I use two replace lines.
Enregistrez le fichier, fermez gedit , puis quittez votre terminal ou fermez-le et démarrez-le pour pouvoir charger le nouveau script que vous avez ajouté.
Accédez au répertoire dans lequel vous souhaitez modifier plusieurs fichiers. Exécutez ensuite:
#replace_string_files_present_dir
Appuyez sur Entrée et cela remplacera automatiquement oldstring et oldstring1 dans tous les fichiers qui les contiennent respectivement avec newstring et newstring1 corrects .
Il sautera tous les répertoires et fichiers qui ne contiennent pas les anciennes chaînes.
Cela pourrait aider à éliminer le travail fastidieux de la saisie au cas où vous disposez de plusieurs répertoires avec des fichiers qui nécessitent un remplacement de chaîne. Tout ce que vous avez à faire est de naviguer vers chacun de ces répertoires, puis d'exécuter:
#replace_string_files_present_dir
Tout ce que vous avez à faire est de vous assurer que vous avez inclus ou ajouté toutes les chaînes de remplacement comme je vous l'ai montré ci-dessus:
replace "oldstring" "newstring" -- *
à la fin du fichier / bin / replace_string_files_present_dir .
Pour ajouter une nouvelle chaîne de remplacement, ouvrez simplement le script que nous avons créé en tapant ce qui suit dans le terminal:
sudo gedit /bin/replace_string_files_present_dir
Ne vous inquiétez pas du nombre de chaînes de remplacement que vous ajoutez, elles n'auront aucun effet si l' ancienne chaîne n'est pas trouvée.
.gitlab-ci.yml
ou a travis.yml
). Chaque virage consistant à écrire un script pour l'exécuter plus tard est un anti-modèle, car vous devrez ensuite scripter la création du script (et je
$ remplace "From" "To" - `find / path / to / folder -type f`
(replace - un utilitaire de remplacement de chaîne du système de base de données MySQL)