acrescentar texto com eco sem nova linha

14

Quero acrescentar texto ao arquivo como echo "abc" >>file.txt.

Mas isso adiciona abcapós nova linha

Como posso adicionar abcno final do arquivo com eco sem nova linha?

choijj
fonte
2
O arquivo já tem uma nova linha, você está apenas adicionando depois dela. Portanto, você terá que substituir o caractere de nova linha da última linha, por "abc".
ctrl-alt-delor
Bem-vindo ao StackExchange! Sua pergunta é boa; teria sido melhor se você especificasse exemplos do conteúdo do seu arquivo (antes da adição, o que você obtém após a adição, o que queria). Digo isso porque uma das respostas é como adicionar abcsem uma nova linha final, que (depois de ler sua pergunta com atenção) não parece ser o que você deseja.
Law29

Respostas:

19

echo "abc" >>file.txtcoloca uma nova linha depois abc , não antes. Se você terminar com abcsua própria linha, isso significa que a nova linha anterior abcjá estava presente file.txt.

Observe que é perfeitamente normal que um arquivo de texto termine em uma nova linha. No unix, uma linha consiste em uma sequência de caracteres que não seja ⁰ ou nova linha seguida por uma nova linha. 1 Portanto, qualquer arquivo de texto não vazio termina com um caractere de nova linha.

Se você deseja adicionar texto à última linha de um arquivo, não pode fazê-lo >>, porque isso sempre se anexa ao arquivo e, portanto, sempre é gravado após a última nova linha. Em vez disso, você precisa de uma ferramenta capaz de modificar um arquivo existente. Por exemplo, você pode usar sed :

sed '$ s/$/abc/' file.txt >file.txt.new && mv file.txt.new file.txt

No comando sed, o primeiro $significa "execute o seguinte comando apenas na última linha", o comando s/REGEX/REPLACEMENT/substitui REGEX por REPLACEMENT, e a expressão regular $corresponde no final da linha.

O comando sed do Linux possui um recurso interno para automatizar essa sequência de criação de novo arquivo e substituição, para que você possa reduzi-lo para

sed -i '$ s/$/abc/' file.txt

Esse é um byte nulo, que ASCII chama NUL e Unicode chama U + 0000. Os programas de processamento de texto podem ou não lidar com esse caractere.
1 Consulte as definições de arquivo de texto , linha e caractere de nova linha na seção "Definições" do capítulo Definições de base da IEEE 1003.1-2008: 2016.

Gilles 'SO- parar de ser mau'
fonte
2
Seu segundo parágrafo significa que um arquivo que não termina com uma nova linha não é um arquivo de texto? Por exemplo, se eu pegar um arquivo de texto ASCII existente que termine com uma nova linha e acrescentar um único byte 0x41(ASCII 'A'), tecnicamente não será mais um arquivo de texto? Nesse caso, sugiro enfatizar esse ponto, já que é uma definição pouco intuitiva; caso contrário, uma pequena alteração na redação pode ajudar a evitar a confusão.
David Z
2
@ DavidD: Essa é a definição padrão de um arquivo de texto no Unixland. IIRC é mesmo em POSIX em algum lugar.
Kevin
1
@ Kevin Interessante, eu nunca tinha ouvido isso antes. Bem, mesmo que seja padrão, eu acho que não é intuitivo.
David Z
15

Eu não acho que é possível com o echocomando, use a seguinte sedabordagem:

sed -i '$ s/$/abc/' file.txt
  • -i- modificar o arquivo no local
  • $ - indica o último registro / linha
  • s/$/abc/ - substitua o final da linha $ por substring abc(para o último registro)
RomanPerekhrest
fonte
2
Observe que "no local" não significa realmente no local. Significa "gravar o conteúdo editado em um arquivo nomeado temporário ao lado do arquivo existente e substituí-lo". Você pode provar isso olhando os inodes comdate >file; ls -i file; sed -i 's/201/ZZZ/' file; ls -i file
roaima
@roaima, eu estou ciente sobre o número de inodes que está mudando.
RomanPerekhrest
2
Eu pensei que você teria ficado, mas eu estava preocupado que, com sua ênfase no local da noite do OP, ele pudesse ser usado para evitar o uso duplo do espaço em disco, por exemplo, com um arquivo grande.
roaima
@roaima, night think -> think think ...
RomanPerekhrest
13

Supondo que o arquivo ainda não termine em uma nova linha e você simplesmente queira acrescentar mais texto sem adicionar um, você pode usar o -nargumento, por exemplo

echo -n "some text here" >> file.txt

No entanto, alguns sistemas UNIX não fornecem essa opção; se for esse o caso, você pode usar printf, por exemplo

printf %s "some text here" >> file.txt

(o %sargumento inicial é proteger contra o texto adicional com %caracteres de formatação)

De man echo(no macOS High Sierra):

-n

Não imprima o caractere de nova linha à direita. Isso também pode ser alcançado anexando '\c'ao final da string, como é feito pelos sistemas compatíveis com o iBCS2. Observe que esta opção e o efeito de '\c'são definidos na implementação na IEEE Std 1003.1-2001 ("POSIX.1"), conforme alterada pela Cor. 1-2002. Os aplicativos que visam a portabilidade máxima são fortemente encorajados a usar printf(1)para suprimir o caractere de nova linha.

fofo
fonte
Obviamente , termina com uma nova linha. echo -nnão colocaria nenhuma nova linha no final de abc, mas abcainda seria precedida por uma nova linha, que é o que o usuário deseja evitar.
Kusalananda
@Kusalananda Minha resposta foi mais usando a suposição de que o OP tentaria mudar seu processo, de modo que o falso \nnão aparecesse em primeiro lugar. Mais opções são melhores, especialmente quando elas não envolvem a necessidade de reescrever o arquivo inteiro toda vez que ocorre uma alteração (que pode ficar bastante lenta e ser executada em tempo polinomial, se for feita repetidamente).
fofo
9

Se você possui o truncatecomando e seu arquivo de texto tem NL como último caractere, você pode removê-lo e anexá-lo da seguinte maneira:

truncate --size -1 file.txt
echo "abc" >>file.txt

(Observe que truncatenada se importa com o conteúdo do arquivo e, neste exemplo, simplesmente reduz o tamanho do arquivo em um byte. Se o seu último caractere não for um único byte, ou seja, é um caractere "amplo" de vários bytes, você apresentará corrupção.)

roaima
fonte
5

O que você deseja é adicioná-lo no final da última linha, logo antes do delimitador dessa última linha, logo antes do último caractere do arquivo.

Com ksh93, você pode fazer:

echo abc 1<> file >#((EOF - 1))

Onde 1<>está o operador padrão para abrir um arquivo no modo de leitura + gravação (e mais importante sem truncamento ) no stdout e >#((...))é um operador de busca específico do ksh93 (aqui para procurar antes do último byte). Observe que echoescreve abc<newline>onde asubstitui a nova linha existente e echoadiciona sua própria nova linha.

O zshequivalente:

zmodload zsh/system
{sysseek -w end -u 1 -1 && echo abc} 1<> file

Embora, para obter um equivalente mais exato, você também precise imprimir uma mensagem de erro quando não conseguir:

zmodload zsh/system
if sysseek -w end -u 1 -1; then
  echo abc
else
  syserror -p "$0: $LINENO: seek: "
fi 1<> file
Stéphane Chazelas
fonte
-1

Provavelmente um UUOC, mas você também pode:

echo "$(cat file.txt)abc" >file.txt

Como Gilles aponta, este comando é limitado:

Isso geralmente funciona, mas não se às vezes houver uma linha em branco no final do arquivo e uma linha em branco imediatamente antes. Por exemplo, um arquivo com um número fixo de linhas, onde a última linha está inicialmente vazia e é estendida ao longo do tempo, e a penúltima linha pode às vezes estar vazia.

Além disso, tenha cuidado ao usar catarquivos que você não conhece:

Conclusão :

Use sed

jesse_b
fonte
2
Isso geralmente funciona, mas não se às vezes houver uma linha em branco no final do arquivo e uma linha em branco imediatamente antes. Por exemplo, um arquivo com um número fixo de linhas, onde a última linha está inicialmente vazia e é estendida ao longo do tempo, e a penúltima linha pode às vezes estar vazia.
Gilles 'SO- stop be evil'
Devo excluí-lo? Eu definitivamente acho que Roman / sua resposta é a maneira correta de ir, mas eu sei que eu pessoalmente gosto de ver as alternativas, e OP pediu echo: p
jesse_b
1
Além disso, este coloca o arquivo inteiro na linha de comando
n.caillou
@ n.caillou hein? Isso não imprimirá nada para STDOUT.
jesse_b
2
Bem, nenhuma dessas vulnerabilidades está realmente relacionada cat, mas a problemas com sequências de escape arbitrárias sendo enviadas para o terminal.
Ilkkachu