Respostas:
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
Ocorrências de "foo" serão substituídas por "bar".
Em sistemas BSD como o macOS, você precisa fornecer uma extensão de backup como -i '.bak'
"risco de corrupção ou conteúdo parcial" por página de manual.
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *
sed
, -i
requer uma sequência após ela, que é anexada aos nomes de arquivos antigos. Então, sed -i .bak 's/foo/bar/g' *.xx
move todos os .xx
arquivos para o .xx.bak
nome equivalente e gera os .xx
arquivos com a substituição foo → bar.
sed -i 's/foo\ with\ spaces/bar/g' *
. Suponho que você tenha descoberto depois de tanto tempo ... mas dessa forma fica para outras pessoas que encontram o mesmo problema.
sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
Semelhante à resposta de Kaspar, mas com o sinalizador g para substituir todas as ocorrências em uma linha.
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
Para caso global insensitivo:
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' {} \;
(ver este post e este )
--include=*.whatever
com -r
.git/
. Certifique-se de cd
descer para um nível mais baixo.
git status
retorna: error: bad index file sha1 signature.... fatal: index file corrupt
. O que da?
A resposta do @ kev é boa, mas afeta apenas os arquivos no diretório imediato. O exemplo abaixo usa grep para localizar arquivos recursivamente. Funciona para mim sempre.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
Divisão de comando
grep -r : --recursive , leia recursivamente todos os arquivos em cada diretório.
grep -l : --print-with-fósforos , imprime o nome de cada arquivo que possui uma correspondência, em vez de imprimir linhas correspondentes.
grep -i : --ignore-case .
xargs : transforme o STDIN em argumentos, siga esta resposta .
O comando xargs -i @ ~ contém @ ~ : um espaço reservado para o argumento a ser usado em uma posição específica no ~ command ~ , o sinal @ é um espaço reservado que pode ser substituído por qualquer string.
sed -i : edita arquivos no local, sem backups.
sed s / regexp / Replacement / : substitui a sequência correspondente de regexp pela substituição .
sed s / regexp / replace / g : global , faça a substituição para cada partida em vez de apenas a primeira partida.
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
|
, também, por que -i
no comando xargs? Eu li no manual que está obsoleto e deve usá-lo -I
. E é @
usado como um delimitador para início e fim para padrão?
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
rli
) e do @
sinal, por exemplo
Isso funcionou para mim:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Howerver, este não fez: sed -i 's/string1/string2/g' *
. Talvez "foo" não tenha sido string1 e "bar" não string2.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Existem algumas respostas padrão para isso já listadas. Geralmente, você pode usar o find para listar recursivamente os arquivos e depois executar as operações com sed ou perl .
Para usos mais rápidos, você pode achar que o comando rpl é muito mais fácil de lembrar. Aqui está a substituição (foo -> bar), recursivamente em todos os arquivos:
rpl -R foo bar .
Você provavelmente precisará instalá-lo ( apt-get install rpl
ou similar).
No entanto, para trabalhos mais difíceis que envolvem expressões regulares e substituição reversa ou renomeação de arquivos, além de pesquisar e substituir, a ferramenta mais geral e poderosa de que conheço é a repren , um pequeno script Python que escrevi há algum tempo. tarefas de renomeação e refatoração mais espinhosas. Os motivos pelos quais você pode preferir são:
Para usá-lo pip install repren
. Verifique o README para exemplos.
Para substituir uma sequência em vários arquivos, você pode usar:
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
Por exemplo
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Para substituir um caminho nos arquivos (evitando caracteres de escape), você pode usar o seguinte comando:
sed -i 's@old_path@new_path@g'
O sinal @ significa que todos os caracteres especiais devem ser ignorados na seguinte sequência.
Caso sua string tenha uma barra (/), você poderá alterar o delimitador para '+'.
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Este comando seria executado recursivamente no diretório atual.
../domain.com
paradomain.com
As ocorrências da primeira linha de "foo" serão substituídas por "bar". E você pode usar a segunda linha para verificar.
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'
Se você tiver uma lista de arquivos, poderá usar
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
Se você tiver todos os arquivos, poderá usar
replace "old_string" "new_string" -- *
Se você tiver uma lista de arquivos com extensão, poderá usar
replace "old_string" "new_string" -- *.extension
replace "old_string" "new_string" -- *.txt
replace
utilitário. Sem essas informações, essa resposta está incompleta.
"Você também pode usar o find e o sed, mas acho que essa pequena linha de perl funciona bem.
perl -pi -w -e 's/search/replace/g;' *.php
"(Extraído de http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php )
Meus melhores resultados vêm do uso de perl e grep (para garantir que o arquivo tenha a expressão de pesquisa)
perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
Como você deseja procurar a sequência search
e substituí-la replace
por vários arquivos, esta é minha fórmula de uma linha testada em batalha :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
Explicação rápida do grep:
-R
- pesquisa recursiva-i
- não diferencia maiúsculas de minúsculas-I
- pule arquivos binários (você quer texto, certo?)-l
- imprima uma lista simples como saída. Necessário para os outros comandosA saída grep é então canalizada para sed (através de xargs), que é usada para substituir o texto. A -i
bandeira alterará o arquivo diretamente. Remova-o para uma espécie de modo "funcionamento a seco".
Eu inventei minha própria solução antes de encontrar esta pergunta (e respostas). Procurei por diferentes combinações de "substituir" "vários" e "xml", porque esse era meu aplicativo, mas não encontrei esse em particular.
Meu problema: tive arquivos xml de primavera com dados para casos de teste, contendo objetos complexos. Um refator no código-fonte java alterou muitas classes e não se aplicava aos arquivos de dados xml. Para salvar os dados dos casos de teste, eu precisava alterar todos os nomes de classe em todos os arquivos xml, distribuídos em vários diretórios. Tudo isso enquanto salvava cópias de segurança dos arquivos xml originais (embora isso não fosse obrigatório, pois o controle de versão me salvaria aqui).
Eu estava procurando por uma combinação de find
+ sed
, porque funcionou para mim em outras situações, mas não com várias substituições ao mesmo tempo.
Então eu encontrei a resposta ask ubuntu e isso me ajudou a construir minha linha de comando:
find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
E funcionou perfeitamente (bem, meu caso teve seis substituições diferentes). Mas observe que ele tocará em todos os arquivos * .xml no diretório atual. Por esse motivo, e se você é responsável por um sistema de controle de versão, convém filtrar primeiro e transmitir apenas aos sed
que realmente possuem as strings que deseja; gostar:
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
será útil.
Realmente idiota, mas não consegui que nenhum dos comandos sed funcionasse corretamente no OSX, então fiz essa coisa idiota:
:%s/foo/bar/g
:wn
^ - copie essas três linhas na minha área de transferência (sim, inclua a nova linha final) e, em seguida:
vi *
e mantenha pressionado o comando-v até que não exista nenhum arquivo.
Burro ... hacky ... eficaz ...
Em um MacBook Pro, usei o seguinte (inspirado em https://stackoverflow.com/a/19457213/6169225 ):
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
garantirá que você não esteja fazendo backups.
-e
para regex moderno.
-e
apenas diz ao sed que o próximo token é um comando. Para expressões regulares estendidas, use em seu -E
lugar.
O editor de fluxo modifica vários arquivos "no local" quando chamado com o -i
comutador, o que leva um arquivo de backup que termina como argumento. assim
sed -i.bak 's/foo/bar/g' *
substitui foo
por bar
todos os arquivos nesta pasta, mas não desce em subpastas. No entanto, isso irá gerar um novo .bak
arquivo para cada arquivo no seu diretório. Para fazer isso recursivamente para todos os arquivos neste diretório e todos os seus subdiretórios, você precisa de um ajudante, como find
, para percorrer a árvore de diretórios.
find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *
find
permite restrições adicionais sobre quais arquivos modificar, especificando outros argumentos como find ./ -name '*.php' -or -name '*.html' -print0
, se necessário.
Nota: O GNU sed
não requer um final de arquivo, sed -i 's/foo/bar/g' *
também funcionará; O FreeBSD sed
exige uma extensão, mas permite um espaço intermediário, assim sed -i .bak s/foo/bar/g *
funciona.
script para comando multiedit
multiedit [-n PATTERN] OLDSTRING NEWSTRING
Com a resposta de Kaspar, criei um script bash para aceitar argumentos da linha de comando e, opcionalmente, limitar os nomes de arquivos correspondentes a um padrão. Salve no seu $ PATH e torne o executável; em seguida, basta usar o comando acima.
Aqui está o 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
Se o arquivo contiver barras invertidas (caminhos geralmente), você pode tentar algo como isto:
sed -i -- 's,<path1>,<path2>,g' *
ex:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Para manter meu nó pessoal em inglês, escrevi um script utilitário que ajuda a substituir vários pares de strings novos / antigos por todos os arquivos em um diretório recursivamente.
O par múltiplo de cadeia antiga / nova é gerenciado em um mapa de hash.
O diretório pode ser definido via linha de comando ou variável de ambiente, o mapa é codificado no script, mas você pode modificar o código para carregar de um arquivo, se necessário.
Requer bash 4.2, devido a algum novo recurso.
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
Usar o comando ack seria muito mais rápido assim:
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
Além disso, se você tiver um espaço em branco no resultado da pesquisa. Você precisa escapar disso.
Estou dando um exemplo para corrigir um erro shebang comum em fontes python.
Você pode tentar a abordagem grep / sed. Aqui está um que funciona com o GNU sed e não quebra um repositório git:
$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}
Ou você pode usar greptile :)
$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .
Acabei de testar o primeiro script e o segundo também deve funcionar. Tenha cuidado com os caracteres de escape, acho que deve ser mais fácil usar o greptile na maioria dos casos. Obviamente, você pode fazer muitas coisas interessantes com o sed e, para isso, pode ser preferível dominar o uso com o xargs.
Encontrei este em outro post (não me lembro qual) e, embora não seja o mais elegante, é simples e, como um usuário iniciante do Linux, não me deu problemas
for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done
se você tiver espaços ou outros caracteres especiais, use a \
for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
para cadeias de caracteres nos subdiretórios use **
for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
Há uma maneira mais fácil usando um arquivo de script simples:
# sudo chmod +x /bin/replace_string_files_present_dir
abra o arquivo no gedit ou em um editor de sua escolha, eu uso o gedit aqui.
# sudo gedit /bin/replace_string_files_present_dir
Em seguida, no editor, cole o seguinte no arquivo
#!/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.
Salve o arquivo, feche o gedit , saia do terminal ou simplesmente feche-o e inicie-o para poder carregar o novo script que você adicionou.
Navegue para o diretório em que você tem vários arquivos que deseja editar. Então corra:
#replace_string_files_present_dir
Pressione enter e isso substituirá automaticamente a cadeia antiga e a cadeia antiga1 em todos os arquivos que as contêm pela nova cadeia e nova cadeia1 respectivamente.
Irá pular todos os diretórios e arquivos que não contêm as strings antigas.
Isso pode ajudar a eliminar o trabalho tedioso de digitar, caso você tenha vários diretórios com arquivos que precisam ser substituídos. Tudo o que você precisa fazer é navegar para cada um desses diretórios e executar:
#replace_string_files_present_dir
Tudo o que você precisa fazer é garantir que você incluiu ou adicionou todas as seqüências de substituição, como mostrei acima:
replace "oldstring" "newstring" -- *
no final do arquivo / bin / replace_string_files_present_dir .
Para adicionar uma nova string de substituição, basta abrir o script que criamos, digitando o seguinte no terminal:
sudo gedit /bin/replace_string_files_present_dir
Não se preocupe com o número de strings de substituição adicionadas, elas não terão efeito se a string antiga não for encontrada.
.gitlab-ci.yml
ou a travis.yml
). Cada turno que consiste em escrever um script para executá-lo mais tarde é um anti-padrão, pois você precisará criar um script para a criação do script (e eu fico confuso, na maioria das vezes)
$ substitua "De" "Para" - `find / path / to / folder -type f`
(replace - um utilitário de substituição de string do MySQL Database System)