Demande-t-il une confirmation avant chaque remplacement?
37
Existe-t-il un moyen de demander à sed de me confirmer avant chaque remplacement? Quelque chose de similaire à 'c' lors de l'utilisation, remplacez à l'intérieur de vim.
Je suis utilise vim (args et argdo) chaque fois que je besoin « confirmation », mais me demandais s'il y avait un « simple » façon
Yuvi
1
Cela va à l’encontre de l’objectif fondamental de sed - d’automatiser l’édition sur un flux.
Teppic
@teppic pas vraiment, car il faudrait tout de même aller chercher les instances dans les fichiers texte, ce que sed peut faire pour vous. Je pense que la question a du sens, juste au cas où vous ajouteriez les mauvais fichiers à une liste et que vous vouliez voir quel fichier vous étiez en
train de
Réponses:
37
Le faire avec sedne serait probablement pas possible car c'est un éditeur de flux non interactif. Envelopper seddans un script nécessiterait beaucoup trop de réflexion. Il est plus facile de le faire simplement avec vim:
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in
Comme cela a été mentionné dans les commentaires ci-dessous, voici comment cela pourrait être utilisé sur plusieurs fichiers correspondant à un modèle particulier de nom de fichier particulier dans le répertoire actuel:
for fname in file*.txt; do
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Ou, si vous voulez d'abord vous assurer que le fichier contient réellement une ligne qui correspond au modèle donné avant de procéder à la substitution,
for fname in file*.txt; do
grep -q 'PATTERN' "$fname" &&
vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done
Les deux boucles ci-dessus modifiées dans des findcommandes qui font la même chose mais pour tous les fichiers avec un nom particulier quelque part dans ou sous un top-dirrépertoire,
find top-dir -type f -name 'file*.txt' \
-exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
Ou, en utilisant les boucles de shell originales et finden leur donnant des noms de chemin d'accès:
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
find top-dir -type f -name 'file*.txt' -exec sh -c '
for pathname do
grep -q "PATTERN" "$pathname" &&
vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
done' sh {} +
En tout cas, vous ne voulez pas faire quelque chose comme for filename in $( grep -rl ... )depuis
il faudrait que cela se greptermine avant même de commencer la première itération de loop, ce qui est inélégant , et
les noms de chemin renvoyés par grepseraient divisés en mots sur des espaces, et ces mots seraient soumis à une annulation de nom de fichier (ce qui disqualifie les noms de chemin contenant des espaces et des caractères spéciaux).
searchandreplace () {
if [ -z $2 ] ; then
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
else
realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
exp=$(realpath * | xargs grep -ins --directories=skip --color=never "$1" | cut -d':' -f1,2 | awk -F':' '{print $2 $1}' | sed -E "s|^[0-9]+|sed -i \'&s/|; s|//|/"$1"/"$2"/g\' /|")
IFS=$'\n'
for d in $exp
do
read -p "Exec $(echo -e -n "\033[1;31m$d\033[0m")? " -e REP
if [ "$REP" = y ]; then
echo `bash -c $d`;
fi
done
fi
}
Si vous alimentez cela avec un seul argument - searchandreplace "AAA"- il ne recherche que cette chaîne dans le répertoire en cours, mais si vous le nourrissez avec un double argument - searchandreplace AAA BBB-, en plus de ce qui précède, il vous demande également de remplacer le premier par le deuxième "ligne par ligne "pour chaque ligne.
Réponses:
Le faire avec
sed
ne serait probablement pas possible car c'est un éditeur de flux non interactif. Enveloppersed
dans un script nécessiterait beaucoup trop de réflexion. Il est plus facile de le faire simplement avecvim
:Comme cela a été mentionné dans les commentaires ci-dessous, voici comment cela pourrait être utilisé sur plusieurs fichiers correspondant à un modèle particulier de nom de fichier particulier dans le répertoire actuel:
Ou, si vous voulez d'abord vous assurer que le fichier contient réellement une ligne qui correspond au modèle donné avant de procéder à la substitution,
Les deux boucles ci-dessus modifiées dans des
find
commandes qui font la même chose mais pour tous les fichiers avec un nom particulier quelque part dans ou sous untop-dir
répertoire,Ou, en utilisant les boucles de shell originales et
find
en leur donnant des noms de chemin d'accès:En tout cas, vous ne voulez pas faire quelque chose comme
for filename in $( grep -rl ... )
depuisgrep
termine avant même de commencer la première itération de loop, ce qui est inélégant , etgrep
seraient divisés en mots sur des espaces, et ces mots seraient soumis à une annulation de nom de fichier (ce qui disqualifie les noms de chemin contenant des espaces et des caractères spéciaux).En relation:
la source
sed
est qu'il peut fonctionner sur plusieurs fichiers, par exemple,sed -i 's/old/new/g' /path/to/*.txt
ou quelque chose de similaire.for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
Vous pouvez l'obtenir en faisant ceci:
Plus précisément, l'ajout
c
du troisième délimiteur.Notez que l'option 'c' ne fonctionne que dans Vim; vous ne pourrez pas l'utiliser avec
sed
la ligne de commande.la source
sed
.vim
, donc cette réponse est applicable; bien que, clairement vim et sed aient des capacités différentesVous pouvez laisser
sed
agir le fichier, puis enregistrer le résultat dans un fichier temporaire que vous pouvez ensuite patcher de manière interactive dans le fichier d'origine à l'aide desdiff
(voir http://www.gnu.org/software/diffutils/manual/diffutils.html # Invoking-sdiff ):la source
Si vous alimentez cela avec un seul argument -
searchandreplace "AAA"
- il ne recherche que cette chaîne dans le répertoire en cours, mais si vous le nourrissez avec un double argument -searchandreplace AAA BBB
-, en plus de ce qui précède, il vous demande également de remplacer le premier par le deuxième "ligne par ligne "pour chaque ligne.la source