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.

Est-ce que Sed fait ça du tout?


3
Ce serait techniquement possible, mais il s’agirait davantage d’un exercice intellectuel que d’une entreprise utile. Voir Comment effectuer un remplacement de texte dans une grande hiérarchie de dossiers? qui a les solutions Vim et Perl.
Gilles 'SO- arrête d'être méchant'

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' {} \;
find top-dir -type f -name 'file*.txt' \
    -exec grep -q 'PATTERN' {} \; \
    -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

  1. 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
  2. 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).

En relation:


2
L'avantage sedest qu'il peut fonctionner sur plusieurs fichiers, par exemple, sed -i 's/old/new/g' /path/to/*.txtou quelque chose de similaire.
user1717828

10
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
tcpaiva

@tecepe, merci de le convertir en réponse, merci.
Nishant

1
@Nishant Ce serait une réponse fragile, car cela éliminerait tout fichier contenant des espaces dans son nom ou son chemin.
Kusalananda

7

Vous pouvez l'obtenir en faisant ceci:

:%s/OLD_TEXT/NEW_TEXT/gc

Plus précisément, l'ajout cdu troisième délimiteur.

Notez que l'option 'c' ne fonctionne que dans Vim; vous ne pourrez pas l'utiliser avec sedla ligne de commande.


4
Pour clarifier: cela ne fonctionne que dans Vim, pas en ligne de commande normale sed.
Brendan

Le PO est étiqueté avec vim, donc cette réponse est applicable; bien que, clairement vim et sed aient des capacités différentes
ILMostro_7


-1
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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.