Esta é provavelmente uma solução complexa .
Estou à procura de um operador simples como ">>", mas de prefixo.
Receio que não exista. Vou ter que fazer algo como
mv myfile tmp cat myheader tmp> myfile
Algo mais inteligente?
Esta é provavelmente uma solução complexa .
Estou à procura de um operador simples como ">>", mas de prefixo.
Receio que não exista. Vou ter que fazer algo como
mv myfile tmp cat myheader tmp> myfile
Algo mais inteligente?
mktemp
? Você sempre pode limpar o arquivo temporário depois ...Respostas:
O truque abaixo foi uma resposta rápida e rápida que funcionou e recebeu muitos votos positivos. Então, à medida que a pergunta se tornou mais popular e com o passar do tempo, pessoas ultrajadas começaram a relatar que meio que funcionava, mas coisas estranhas podiam acontecer, ou simplesmente não funcionavam, por isso foi furiosamente rejeitada por um tempo. Que divertido.
A solução explora a implementação exata dos descritores de arquivo no seu sistema e, como a implementação varia significativamente entre os nixes, seu sucesso depende totalmente do sistema, definitivamente não é portátil e não deve ser considerado algo vagamente importante.
Agora, com tudo isso fora do caminho, a resposta foi:
A criação de outro descritor de arquivo para o arquivo (
exec 3<> yourfile
), portanto, a gravação nesse arquivo ( )>&3
parece superar a leitura / gravação no mesmo dilema de arquivo. Funciona para mim em arquivos de 600K com awk. No entanto, tentar o mesmo truque usando 'gato' falha.Passar o prefácio como uma variável para awk (
-v TEXT="$text"
) supera o problema de aspas literais, o que evita fazer esse truque com 'sed'.fonte
Isso ainda usa um arquivo temporário, mas pelo menos está em uma linha:
Crédito: BASH: anexar um texto / linhas a um arquivo
fonte
-
depoiscat
?echo -n "text"
yourfile
for um link simbólico, isso não fará o que você deseja.ed é o editor padrão! http://www.gnu.org/fun/jokes/ed.msg.html
fonte
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee: não é garantido que seu método funcione e provavelmente falhará se você acrescentar mais de 4096 bytes de material (pelo menos é o que acontece com o gnu awk, mas suponho que outras implementações tenham restrições semelhantes). Não apenas falhará nesse caso, como também entrará em um loop infinito, onde lerá sua própria saída, aumentando o arquivo até que todo o espaço disponível seja preenchido.
Experimente você mesmo:
(aviso: mate-o depois de um tempo ou ele irá preencher o sistema de arquivos)
Além disso, é muito perigoso editar arquivos dessa maneira, e é um péssimo conselho, como se algo acontecesse enquanto o arquivo estava sendo editado (falha, disco cheio). Você quase garante que o arquivo fique em um estado inconsistente.
fonte
Não é possível sem um arquivo temporário, mas aqui vai um oneliner
Você pode usar outras ferramentas, como ed ou perl, para fazer isso sem arquivos temporários.
fonte
Vale a pena notar que muitas vezes é um boa ideia gerar o arquivo temporário com segurança usando um utilitário como mktemp , pelo menos se o script for executado com privilégios de root. Você pode, por exemplo, fazer o seguinte (novamente no bash):
fonte
Se você precisar disso nos computadores que você controla, instale o pacote "moreutils" e use "sponge". Então você pode fazer:
fonte
{ echo "prepended text"; cat myfile } | sponge myfile
Usando um heredoc bash, você pode evitar a necessidade de um arquivo tmp:
Isso funciona porque $ (cat myfile) é avaliado quando o script bash é avaliado, antes que o gato com redirecionamento seja executado.
fonte
assumindo que o arquivo que você deseja editar seja my.txt
E o arquivo que você deseja anexar é o cabeçalho
Certifique-se de ter uma linha em branco final no arquivo de cabeçalho.
Agora você pode anexá-lo com
Você acaba com
Até onde eu sei, isso só funciona no 'bash'.
fonte
this is the header
em my.txt. Mesmo depois de atualizar o Bash para4.3.42(1)-release
obter o mesmo resultado.<(...)
do processo ( ) grava, então não há garantia de quemy.txt
seja lido na íntegra , sem o qual essa técnica não funcionará.Quando você começa a tentar fazer coisas que se tornam difíceis no shell-script, sugiro enfaticamente reescrever o script em uma linguagem de script "adequada" (Python / Perl / Ruby / etc)
Quanto à adição de uma linha a um arquivo, não é possível fazer isso por meio de canalização, pois quando você faz algo assim
cat blah.txt | grep something > blah.txt
, inadvertidamente, o arquivo é apagado. Existe um pequeno comando utilitário chamadosponge
você pode instalar (você instalacat blah.txt | grep something | sponge blah.txt
e ele armazena em buffer o conteúdo do arquivo, depois o grava no arquivo). É semelhante a um arquivo temporário, mas você não precisa fazer isso explicitamente. mas eu diria que é um requisito "pior" do que, digamos, Perl.Pode haver uma maneira de fazê-lo via awk, ou similar, mas se você precisar usar o shell-script, acho que um arquivo temporário é de longe a maneira mais fácil (/ somente?).
fonte
Como Daniel Velkov sugere, use tee.
Para mim, essa é uma solução inteligente simples:
fonte
EDIT: Isso está quebrado. Consulte Comportamento estranho ao anexar um arquivo com cat e tee
A solução alternativa para o problema de substituição está usando
tee
:fonte
O que eu uso. Este permite especificar pedidos, caracteres extras, etc. da maneira que você gosta:
PS: só não está funcionando se os arquivos contiverem texto com barra invertida, pois será interpretado como caracteres de escape
fonte
Principalmente por diversão / golfe, mas
fará o truque e não há pipelines ou redirecionamentos. Obviamente, o vi / ex não é realmente para uso não interativo; portanto, o vi piscará brevemente.
fonte
Por que não simplesmente usar o comando ed (como já sugerido pelo fluffle aqui)?
ed lê o arquivo inteiro na memória e executa automaticamente uma edição no local!
Então, se seu arquivo não for tão grande ...
Outra solução alternativa seria usar identificadores de arquivo aberto, conforme sugerido por Jürgen Hötzel na saída Redirect from sed 's / c / d /' myFile para myFile
Tudo isso pode ser colocado em uma única linha, é claro.
fonte
Uma variante da solução da cb0 para "no file temp" para anexar um texto fixo:
Novamente, isso depende da execução do sub-shell - o (..) - para evitar que o gato se recuse a ter o mesmo arquivo para entrada e saída.
Nota: Gostei desta solução. No entanto, no meu Mac, o arquivo original é perdido (pensei que não deveria, mas existe). Isso pode ser corrigido escrevendo sua solução como: echo "text to prefpend" | cat - file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified
fonte
Aqui está o que eu descobri:
fonte
fonte
AVISO: isso precisa de um pouco mais de trabalho para atender às necessidades do OP.
Deve haver uma maneira de fazer a abordagem sed do @shixilun funcionar, apesar de suas dúvidas. Deve haver um comando bash para escapar do espaço em branco ao ler um arquivo em uma sequência substituta sed (por exemplo, substituir caracteres de nova linha por '\ n'. Comandos do shell
vis
ecat
pode lidar com caracteres não imprimíveis, mas não em espaço em branco, para que isso não resolva os OPs problema:falha devido às novas linhas brutas no script substituto, que precisam ser anexadas com um caractere de continuação de linha () e talvez seguidas de um &, para manter o shell e sed felizes, como esta resposta SO
sed
possui um limite de tamanho de 40 K para comandos de substituição de pesquisa não globais (sem rastreamento / g após o padrão), portanto, provavelmente evitaria os problemas assustadores de saturação de buffer do awk que o anônimo alertou.fonte
fonte
Com $ (comando), você pode gravar a saída de um comando em uma variável. Então eu fiz isso em três comandos em uma linha e sem arquivo temporário.
fonte
Se você possui um arquivo grande (algumas centenas de kilobytes no meu caso) e acesso ao python, isso é muito mais rápido que as
cat
soluções de pipe:python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'
fonte
Uma solução com
printf
:Você também pode fazer:
Mas, nesse caso, você deve ter certeza de que não há nenhum
%
lugar, incluindo o conteúdo do arquivo de destino, pois isso pode ser interpretado e estragar seus resultados.fonte
echo
parece ser uma opção mais segura.echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
, não o arquivo de destinoVocê pode usar a linha de comando perl:
Onde -i criará uma substituição embutida do arquivo e -0777 engolirá o arquivo inteiro e fará ^ corresponder apenas ao início. -pe imprimirá todas as linhas
Ou se my_header for um arquivo:
Onde o / e permitirá uma avaliação do código na substituição.
fonte
onde "meu_arquivo" é o arquivo para o qual preceder "minha_string".
fonte
Estou gostando da abordagem ed da @ fluffle da melhor da . Afinal, as opções de linha de comando de qualquer ferramenta e os comandos do editor com script são essencialmente a mesma coisa aqui; não vendo uma solução de editor com script "limpeza" ser menor ou mais do que isso.
Aqui está o meu one-liner anexado a
.git/hooks/prepare-commit-msg
um.gitmessage
arquivo in-repo para confirmar as mensagens:Exemplo
.gitmessage
:Estou fazendo isso em
1r
vez de0r
, porque isso deixará a linha vazia pronta para gravação na parte superior do arquivo do modelo original. Não coloque uma linha vazia em cima do seu.gitmessage
, pois você terminará com duas linhas vazias.-s
suprime a saída de informações de diagnóstico de ed.Em conexão com isso, descobri que para o vim-buffs também é bom ter:
fonte
variáveis, ftw?
fonte
Eu acho que esta é a variação mais limpa de ed:
Como uma função:
fonte
Se você estiver criando scripts no BASH, na verdade, poderá emitir:
Na verdade, isso está no Exemplo complexo que você postou em sua própria pergunta.
fonte
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
, no entanto, isso é suficientemente diferente da minha resposta para que seja sua própria resposta.IMHO não há solução shell (e nunca será uma) que funcionaria de forma consistente e confiável, independentemente do tamanho dos dois arquivos
myheader
emyfile
. O motivo é que, se você quiser fazer isso sem retornar a um arquivo temporário (e sem permitir que o shell ocorra silenciosamente em um arquivo temporário, por exemplo, através de construções comoexec 3<>myfile
, canalizar paratee
etc.)A solução "real" que você está procurando precisa mexer com o sistema de arquivos e, portanto, não está disponível no espaço do usuário e depende da plataforma: você está pedindo para modificar o ponteiro do sistema de arquivos em uso pelo
myfile
valor atual do ponteiro do sistema de arquivos paramyheader
e substitua no sistemaEOF
de arquivos o demyheader
por um link encadeado para o endereço atual do sistema de arquivos apontado pormyfile
. Isso não é trivial e, obviamente, não pode ser feito por um não-superusuário, e provavelmente pelo superusuário também ... Jogue com inodes, etc.Você pode mais ou menos fingir isso usando dispositivos de loop, no entanto. Veja, por exemplo, este segmento SO .
fonte