Não é possível colocar uma string em um arquivo em uma string de outro arquivo

3

Encontrei um problema estranho ao concatenar os arquivos usando o comando cat . Eu tenho dois arquivos com uma string em cada um deles:

arquivo1:

ABC

arquivo2:

DEF

Ou eu faço cat file1 file2 ou eu faço cat file1 >> file2 . Espero uma saída como mostrado abaixo:

ABC  
DEF

No entanto, tenho uma saída engraçada como esta:

ABCDEF

Eu verifiquei os arquivos e não há espaço extra ou caracteres. No entanto, quando faço a exclusão manual da parte de trás da string, nem vejo um único caractere. Funciona bem. Eu suponho que deve haver algum tipo de linha "oculta" ou linha que não posso ver.

Isso tem me incomodado muito porque eu tenho muitos arquivos para concatenar. Eu não posso fazer a mesma coisa manualmente.

Qualquer ajuda é apreciada.

    
por bison72 12.07.2015 / 14:29

4 respostas

5

paste é provavelmente o mais fácil (que, para não mencionar, extremamente eficiente) significa à sua disposição para lidar com esse problema.

printf abc >file1
printf def >file2
paste -sd\n file[12]
abc
def

Quando paste é invocado -s erialmente, ele lerá cada um de seus arquivos de entrada nomeados por vez e paste da saída de cada linha dentro de cada arquivo em uma guia < tab > ou uma string% elimiter -d especificada. Enquanto paste sempre terminará sua saída de cada infile nomeado com um \n ewline, aqui o -d elimiter também é especificado para ser um \n ewline e, portanto, será basicamente cat sua entrada para a saída com a exceção de que cada arquivo sempre terminará em \n ewline.

Como Peter aponta abaixo, um arquivo vazio pode fazer com que paste emita um extra \n ewline. Se isso for um problema, praticamente o mesmo método pode ser aplicado com sed , o que não será :

: > file0
sed '' file[012]
abc
def

Agora com este método, (com GNU sed pelo menos) pode haver um problema diferente. Qualquer sed irá sempre escrever um \n ewline antes de puxar outra linha, mas se for a muito última linha de toda a série concatenada de arquivos de entrada, então alguns sed s (como o GNU) podem não anexar uma nova linha no final. Por exemplo, com meus arquivos de entrada, o def não é seguido por uma nova linha.

E se isso é um problema, bem ...

sed '' file[012] | paste -sd\n

... o canal acima provavelmente deve cobrir todas as suas bases.

    
por 12.07.2015 / 19:02
1

Como Peter diz, seu primeiro arquivo não tem um caractere de final de linha. Você provavelmente pode verificar com ls -l --- se são exatamente três caracteres, é isso.

Se você quiser "cat" os arquivos adicionando uma nova linha somente se a nova linha não estiver lá, você pode usar o truque legal explicado aqui .

Se você tiver esses três arquivos:

[romano:~/tmp] % ls -l f1 f2 f3
-rw-rw-r-- 1 romano romano 3 Jul 12 14:58 f1
-rw-rw-r-- 1 romano romano 4 Jul 12 15:03 f2
-rw-rw-r-- 1 romano romano 4 Jul 12 15:03 f3
[romano:~/tmp] % cat f1 f2 f3
ABCDEF
GHI

onde f1 não tem fim de linha na última linha, enquanto os outros fazem, você pode fazer:

[romano:~/tmp] % sed -e '$a\' f1 f2 f3
ABC
DEF
GHI

... sed é um EDI de Fluxo, e você está instruindo para imprimir todos inalterados e a última linha adicionando nada --- mas sed implicitamente adiciona uma nova linha quando opera, então resolve o problema.

Observe que apenas o uso da coisa cat + echo adicionará uma nova linha sempre . então você terá dois onde você teve um:

[romano:~/tmp] % for i in f?; do cat $i; echo; done;
ABC
DEF

GHI

[romano:~/tmp] %
    
por 12.07.2015 / 15:15
1

Parece que o seu file1 não tem nova linha à direita. Se você quiser concatenar uma lista de arquivos. Você pode primeiro verificar cada um deles e cat uma nova linha, conforme necessário, da seguinte maneira:

# make some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" ghi > file3
printf "%s"   jkl > file4  # no trailing newline
# find files to concatenate and build a sorted array 'f[]'
unset f i; 
while IFS= read -r -d $'
abc
def
ghi
jkl
' path; do f[i++]="$path" done < <(find . -type f -name 'file[0-9]' -print0 | sort -z) # build the 'cat' command cmd=cat tmp="$(mktemp)"; echo >$tmp # a file which contains only '\n' for file in "${f[@]}"; do lasthex=$(tail -c1 $file | hexdump -ve '1/1 "%02x"') [[ -z $lasthex ]] && continue # skip enpty files [[ $lasthex == 0a ]] && nl= || nl=" $tmp" cmd="$cmd \"$file\"$nl" done # execute the 'cat' command eval "$cmd"

O resultado concatenado é:

cat "./file1" "./file2" /tmp/tmp.z7iKccY0T9 "./file3" "./file4" /tmp/tmp.z7iKccY0T9

O comando gerado é:

# make some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" ghi > file3
printf "%s"   jkl > file4  # no trailing newline
    
por 12.07.2015 / 15:19
0

Você está perdendo novas linhas. Você poderia fazer

cat file1; echo; cat file2;

ou crie um arquivo que tenha apenas um linebrake e faça

cat file1 NEWLINEFILE file2

ou faça isso com um loop como este

for i in find[1-2]; do cat $i; echo; done;

para percorrer *, catar cada arquivo e adicionar uma nova linha posteriormente.

Com $(find OPTIONS) em vez de find[1-2] , você pode refinar sua seleção.

    
por 12.07.2015 / 15:00

Tags