Procura e substitui do terminal, mas com confirmação

4

Em muitos editores de texto, você pode pesquisar e substituir e receber a opção de inspecionar cada caso encontrado. Eu gostaria de poder fazer algo semelhante a isso na linha de comando do Ubuntu. Eu sei sed oferece a capacidade de localizar e substituir seqüências de caracteres em vários arquivos, mas existe de qualquer maneira para ter cada substituição confirmada pelo usuário?

Idealmente, gostaria de uma solução que me permitisse fazer isso "solicitado" para localizar e substituir todos os arquivos em um diretório.

    
por random_forest_fanatic 25.02.2015 / 07:34

4 respostas

7

Que tal o Vim?

vim '+%s/set/bar/gc' some_file
  • + é usado para executar um comando após o carregamento do arquivo.
  • % executa o comando sobre todo o buffer (arquivo).
  • gc são sinalizadores para :substitute , g para atuar sobre todas as expressões na linha e c para confirmar cada substituição.

Você não pode impedir que o Vim abra o arquivo, mas você pode automatizar salvar e sair:

vim '+bufdo %s/set/bar/gc | up' '+q' some_file another_file
  • bufdo executa o comando sobre cada buffer. Isso inclui a parte após | , então as alterações em cada buffer são salvas ( up ) .
  • q quits, que sai do Vim desde que estamos agora no último buffer.
por muru 25.02.2015 / 08:04
4

Você pode usar a combinação de pesquisa e seu comando -ok . Este comando é o mesmo que o comando -exec , mas pergunta ao usuário antes da execução de cada comando especificado. Se o usuário concordar, execute o comando. Caso contrário, apenas retorne falso.

de man find :

-ok command ;
      Like  -exec  but ask the user first. If the user agrees, run the command. 
      Otherwise just return false. If the command is run, its standard input is 
      redirected from /dev/null.

Então, você pode usar o comando da seguinte forma:

$ find ./ -name filename -ok sed 's/foo/bar/' {} \;
< sed ... filename > ?

isto irá avisar o usuário como mostrado na segunda linha acima.

Se você inserir y , o comando sed replacement será executado e sua substituição será feita. Se você inserir n , o comando -ok ignorará o comando sed.

Se você quiser fazer isso "solicitado" find e replace em todos os arquivos dentro de um diretório, use o comando da seguinte forma:

$ find /path/to/directory -type f -ok sed 's/foo/bar/' {} \;
    
por αғsнιη 05.03.2015 / 14:15
2

Gostaria apenas de escrever um pequeno script em Perl:

#!/usr/bin/env perl
use strict;
use warnings;

my $pat="$ARGV[0]";
my $replacement=$ARGV[1];
my $file="$ARGV[2]";

## Open the input file
open(my $fh, "$file");

## Read the file line by line
while (<$fh>) {
    ## If this line matches the pattern
    if (/$pat/) {
        ## Print the current line
        print STDERR "Line $. : $_";
        ## Prompt the user for an action
        print STDERR "Substitute $pat with $replacement [y,n]?\n";
        ## Read the user's answer
        my $response=<STDIN>;
        ## Remove trailing newline
        chomp($response);
        ## If the answer is y or Y, make the replacement.
        ## All other responses will be ignored. 
        if ($response eq 'Y' || $response eq 'y') {
            s/$pat/$replacement/g;
        }    
    }
    ## Print the current line. Note that this will 
    ## happen irrespective of whether a replacement occured.
    print;
}

Salve o arquivo como ~/bin/replace.pl , torne-o executável com chmod a+x ~/bin/replace.pl e execute-o com o padrão para corresponder como o primeiro argumento, a substituição como o segundo e o nome do arquivo como o terceiro:

replace.pl foo bar file > newfile

Para executá-lo em vários arquivos, por exemplo, todos os arquivos *.txt , envolva-os em um loop bash:

for file in *txt; do 
    replace.pl foo bar "$file" > "$file".new
done

E para editar o arquivo "no lugar":

for file in *txt; do 
    tmp=$(mktemp)
    replace.pl foo bar "$file" > "$tmp" && mv "$tmp" "$file"
done
    
por terdon 05.03.2015 / 14:00
0

Você pode combinar a sugestão de muru para usar o vim com Sugestão do AFSHIN para usar find (que tem a vantagem de recursionar em subdiretórios), por exemplo:

find ./ -type f -exec vim -c '%s/originalstring/replacementstring/gc' -c 'wq' {} \;
    
por Anurag Bihani 08.08.2017 / 09:26