Basicamente, quero pegar como texto de entrada de um arquivo, remover uma linha desse arquivo e enviar a saída de volta para o mesmo arquivo. Algo nessa linha se isso torna mais claro.
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name
entretanto, quando faço isso, acabo com um arquivo em branco. Alguma ideia?
Respostas:
Você não pode fazer isso porque o bash processa os redirecionamentos primeiro e, em seguida, executa o comando. Então, no momento em que grep olha para file_name, ele já está vazio. Você pode usar um arquivo temporário.
assim, considere usar
mktemp
para criar o tmpfile, mas observe que não é POSIX.fonte
>
redirecionamento abrirá o arquivo e o truncará antes que o shell seja iniciadogrep
.sponge
comando deve ser aceita.Use uma esponja para este tipo de tarefas. É parte do moreutils.
Tente este comando:
fonte
brew install moreutils
.sudo apt-get install moreutils
em sistemas baseados em Debian.Em vez disso, use sed:
fonte
-i
é uma extensão GNU apenas, apenas observando.-i ''
que a extensão não é estritamente obrigatória, mas a-i
opção requer algum argumento.tente este simples
Seu arquivo não ficará em branco desta vez :) e sua saída também será impressa em seu terminal.
fonte
/dev/null
ou locais semelhantes.Você não pode usar o operador de redirecionamento (
>
ou>>
) para o mesmo arquivo, porque ele tem uma precedência mais alta e irá criar / truncar o arquivo antes mesmo de o comando ser invocado. Para evitar isso, você deve usar as ferramentas adequadas, tais comotee
,sponge
,sed -i
ou qualquer outra ferramenta que pode escrever resultados para o arquivo (por exemplosort file -o file
).Basicamente, redirecionar a entrada para o mesmo arquivo original não faz sentido e você deve usar editores apropriados no local para isso, por exemplo, editor Ex (parte do Vim):
Onde:
'+cmd'
/-c
- executa qualquer comando Ex / Vimg/pattern/d
- remove as linhas que correspondem a um padrão usando global (help :g
)-s
- modo silencioso (man ex
)-c wq
- executar:write
e:quit
comandosVocê pode usar
sed
para atingir o mesmo (como já demonstrado em outras respostas), no entanto in-place (-i
) é a extensão FreeBSD não-padrão (pode funcionar de forma diferente entre Unix / Linux) e, basicamente, é uma s tream ed itor, não um editor de arquivos . Veja: O modo Ex tem alguma utilidade prática?fonte
Uma alternativa de linha - defina o conteúdo do arquivo como variável:
fonte
Uma vez que esta pergunta é o principal resultado nos motores de busca, aqui está um one-liner baseado em https://serverfault.com/a/547331 que usa um subshell em vez de
sponge
(que geralmente não faz parte de uma instalação vanilla como o OS X) :O caso geral é:
Editar, a solução acima tem algumas ressalvas:
printf '%s' <string>
deve ser usado em vez deecho <string>
para que os arquivos que contenham-n
não causem comportamento indesejado.x
à saída e removê-lo do lado de fora via expansão de parâmetro de uma variável temporária como${v%x}
.$v
pisa o valor de qualquer variável existente$v
no ambiente shell atual, portanto, devemos aninhar a expressão inteira entre parênteses para preservar o valor anterior.null
na saída. Eu verifiquei isso chamandodd if=/dev/zero bs=1 count=1 >> file_name
e visualizando em hexadecimal comcat file_name | xxd -p
. Masecho $(cat file_name) | xxd -p
está despojado. Portanto, esta resposta não deve ser usada em arquivos binários ou qualquer coisa que use caracteres não imprimíveis, como Lynch apontou .A solução geral (albiet ligeiramente mais lento, mais memória intensiva e ainda removendo caracteres não imprimíveis) é:
Teste em https://askubuntu.com/a/752451 :
Deve imprimir:
Enquanto chamando
cat file_uniquely_named.txt > file_uniquely_named.txt
o shell atual:Imprime uma string vazia.
Não testei isso em arquivos grandes (provavelmente com mais de 2 ou 4 GB).
Peguei emprestada essa resposta de Hart Simha e kos .
fonte
cat
e o coloca como primeiro argumento paraecho
. É claro que as variáveis não imprimíveis não sairão corretamente e corromperão os dados. Não tente redirecionar um arquivo para ele mesmo, simplesmente não pode ser bom.Também existe
ed
(como alternativa ased -i
):fonte
Você pode fazer isso usando a substituição de processo .
É um pouco um hack, já que o bash abre todos os canais de forma assíncrona e temos que contornar isso usando
sleep
YMMV.No seu exemplo:
>(sleep 1 && cat > file_name)
cria um arquivo temporário que recebe a saída do grepsleep 1
demora por um segundo para dar tempo ao grep para analisar o arquivo de entradacat > file_name
escreve a saídafonte
Você pode usar slurp com POSIX Awk:
Exemplo
fonte
Isso é muito possível, você só precisa ter certeza de que, no momento de escrever a saída, está gravando em um arquivo diferente. Isso pode ser feito removendo o arquivo depois de abrir um descritor de arquivo nele, mas antes de gravá-lo:
Ou linha por linha, para entender melhor:
Ainda é uma coisa arriscada de se fazer, porque se COMMAND não funcionar corretamente, você perderá o conteúdo do arquivo. Isso pode ser atenuado restaurando o arquivo se COMMAND retornar um código de saída diferente de zero:
Também podemos definir uma função shell para torná-la mais fácil de usar:
Exemplo:
Além disso, observe que isso manterá uma cópia completa do arquivo original (até que o terceiro descritor de arquivo seja fechado). Se você estiver usando Linux e o arquivo no qual está processando for muito grande para caber duas vezes no disco, você pode verificar este script que canalizará o arquivo para o comando especificado bloco a bloco enquanto desaloca o já processado blocos. Como sempre, leia os avisos na página de uso.
fonte
Tente isto
fonte
O seguinte realizará a mesma coisa
sponge
, sem exigirmoreutils
:A
--random-source=/dev/zero
parte funciona como um truqueshuf
sem fazer qualquer embaralhamento, portanto, armazenará em buffer sua entrada sem alterá-la.No entanto, é verdade que usar um arquivo temporário é melhor, por motivos de desempenho. Então, aqui está uma função que escrevi que fará isso para você de uma forma generalizada:
fonte
Eu costumo usar o programa tee para fazer isso:
Ele cria e remove um arquivo temporário sozinho.
fonte
tee
não é garantido que funcione. Consulte askubuntu.com/a/752451/335781 .