Estou tentando alterar uma string em vários arquivos de texto (configurações migradas para outro usuário). Eu usei este comando:
grep -iIlr "/home/user/.local" | xargs sed -i 's/\/home\/user\/\.local/~\/\.local/g'
também tentei isso:
grep -iIlr "/home/user/.local" | xargs -d '\n' sed -i "s/\/home\/user\/\.local/~\/\.local/g"
Eles não funcionam. Erros são produzidos por sed , a saída do comando é:
sed: can't read dir/file1: No such file or directory
sed: can't read dir/file2: No such file or directory
...
sed: can't read dir/file99: No such file or directory
O erro é produzido para cada arquivo (99 no total). O dir/file1..99 retornado é válido, é o caminho e nome de arquivo adequados para os arquivos.
grep sozinho produz a lista adequada de arquivos. Não há caracteres especiais nos nomes dos arquivos, acho que também não há espaços (não tenho certeza sobre isso). O xargs não está passando uma lista adequada?
SO: RHEL 8.10 totalmente atualizado,
GNU grep v 3.1,
GNU sed 4.5,
xargs (GNU findutils) 4.6.0
Adicionando a saída (exemplo das últimas linhas) do grep -iIlr "/home/user/.local"
comando.
senha,~/.local/pipx
venvs/pipx/bin/pipx
venvs/pipx/bin/activate.fish
venvs/pipx/bin/activate-global-python-argcomplete
venvs/pipx/bin/activate.csh
venvs/pipx/pyvenv.cfg
venvs/pipx/lib/python3.11/site-packages/pipx_shared.pth
shared/bin/pip3.11
shared/bin/activate
shared/bin/pip3
shared/bin/pip
shared/bin/wheel
shared/bin/activate.fish
shared/bin/activate.csh
shared/pyvenv.cfg
Depois que meu cérebro quase derreteu,
O problema era este:
Portanto, a saída do grep incluiu algumas sequências de escape para color que xargs + sed não conseguiu analisar. Meus olhos viram cores bonitas :)
\grep
ouunalias grep
resolveu o problema.xargs
por padrão, espera uma entrada em um formato muito específico, onde os argumentos devem ser separados por caracteres de espaço em branco (cuja lista depende daxargs
implementação e do local, embora no caso do GNUxargs
seja limitado a espaço, tabulação e nova linha) e onde único aspas aspas duplas e barra invertida podem ser usadas para escapar delas (embora de uma maneira única).Definitivamente, esse não é o formato da lista de arquivos gerados por
grep -rl
.Com
-d '\n'
(uma extensão GNU), o formato muda para ser delimitado por nova linha, sem nenhuma maneira de escapar da nova linha. Esse é o formato gerado porgrep -rl
, mas ainda não funciona para nomes de arquivos que contêm caracteres de nova linha. A saída degrep -rl
simplesmente não é pós-processável de forma confiável para nomes de arquivos arbitrários.GNU
grep
(e você já está usando alguns GNUisms) tem uma opção-Z
/ para gerar a lista de arquivos de uma forma pós-processável com a qual você pode combinar (também extensões GNU, mas mais portáveis que ):--null
-l
xargs -r0
-d
Também removi a
-i
opção degrep
que os caminhos de arquivo diferenciam maiúsculas de minúsculas na maioria dos sistemas do tipo Unix, incluindo RHEL e você não está usando oi
sinalizador parased
'ss
de qualquer maneira, adicionei a-F
correspondência de string fixa for (para evitar ter que escapar do.
regexp operador). Adicionado\>
o limite do Word para que não corresponda ao/home/user/.local
interior/home/user/.locale
, por exemplo (embora ainda corresponda ao interior/home/user/.local-tmp
), especificou explicitamente em qual diretórior
procurar ecursivamente (para maior clareza e compatibilidade com versões mais antigas do GNUgrep
) e adicionou algumas capturas, recuperadas com\1
.Seu problema foi explicado por você ter um
grep='grep --color=yes'
alias em vez degrep='grep --color=auto'
ougrep='grep --color'
o que significa quegrep
as saídas colorem sequências de escape mesmo quando sua saída não vai diretamente para um terminal.Existem outras explicações possíveis.
Os arquivos
~/.local
são gravados por muitos aplicativos, os arquivos são adicionados e removidos à vontade por eles; entregrep
encontrar arquivos esed
processá-los, alguns desses arquivos poderiam muito bem ter desaparecido.Cuidado também,
sed -i
não edita arquivosi
no local, ele os substitui por uma cópia editada. Se alguns aplicativos tiverem os arquivos que você está editando abertos, eles continuarão vendo a cópia original (agora excluída) e qualquer alteração que fizerem a partir de agora será perdida.sed -i
também quebra links físicos e links simbólicos (embora o GNUgrep -r
não analise links simbólicos).Substituir
/home/user
por~
também muitas vezes não é uma coisa válida a se fazer. A expansão do til é algo feito por shells (a maioria dos shells atualmente) e alguns outros aplicativos, mas certamente não todos. Fora deles,~/.local/file
é chamado o caminho dofile
arquivo dentro do.local
subdiretório de um subdiretório do diretório de trabalho atual~
(como aftermkdir -p '~/.local' && touch '~/.local/file'
). Portanto, a substituição/home/user/.local
por~/.local
provavelmente interromperá muitos aplicativos.Lembre-se também de que o GNU
grep
-I
para pular arquivos binários usa heurística e não é infalível (de qualquer forma, pode fornecer falsos positivos e falsos negativos). Alguns formatos baseados em texto, como o formato de serialização de dados PHP, serão quebrados se você substituir uma string por outra de comprimento diferente.