Forçar novas linhas com a impressão curinga de gato

9

Eu quero usar gato com curingas no bash para imprimir vários arquivos pequenos (cada arquivo é uma frase) para a saída padrão. No entanto, o conteúdo do arquivo separado não é separado por uma nova linha, o que eu gostaria para facilitar a leitura.

Como posso adicionar um delimitador de arquivo de algum tipo a este comando?

lennyklb
fonte

Respostas:

12

Defina uma função shell que gera um final de linha após cada arquivo e use-a em vez de cat:

endlcat() {
  for file in "$@"; do
    cat -- "$file"
    echo
  done
}

então você pode usar endlcat *.

O forloop faz um loop sobre todos os argumentos fornecidos ( $@) que já são escapados pelo shell quando você usa caracteres curinga *. O --é necessário para não engasgar com nomes de arquivos que começam com um traço. Finalmente, a echosaída é uma nova linha.

Marco
fonte
Parece bastante óbvio usar a iteração em retrospectiva! Eu pensei que poderia ter havido uma bandeira no gato, mas isso funciona também! Obrigado.
lennyklb
Você não precisa do in "$@"- está implícito.
L0b0 14/10/2015
4
ser explícito é bom para facilitar a leitura.
cas
5

Basta usar um loop em vez de simples cat:

for file in /path/to/targetdir/*; do
    echo "-------- $file -------"
    cat "$file" 
done
terdon
fonte
Funciona como a resposta aceita, mas essa também teve o próximo passo para a linha de comando, então eu aceitei a outra.
lennyklb
3

Se você quiser o nome do arquivo entre os arquivos, use tail:

tail -n +1 ./*

(Caso você queira, em tacvez de cat, alguma tailimplementação tem -ropção para tacfuncionalidade equivalente )

cuonglm
fonte
3

Isso funcionará:

sed '' -- *

Você não precisa de nenhum loop de shell ou não, e isso sempre seguirá a saída de um arquivo com uma linha de \new - exceto, talvez, a última.

Caso contrário, se você desejar que uma linha em branco seja impressa entre a saída de cada arquivo, isso poderá funcionar:

bpaste(){
    eval "paste -'sd\n' -- $(x=0;for f do printf "\"\${$((x+=1))}\" - ";done)"
}   </dev/null

Isso sempre seguirá a saída de um arquivo com uma linha \new e uma linha em branco adicional .

Você pode chamar assim:

bpaste *
mikeserv
fonte
@cuonglm - o op quer uma nova linha entre os arquivos. isso garante uma nova linha entre arquivos.
mikeserv
@cuonglm - você deve tentar novamente. for n in 1 2 3; do printf "$n" >"$n"; done; sed '' -- [123]
mikeserv
@cuonglm - qualquer um seddeve sempre imprimir uma linha \neletrônica antes de imprimir qualquer outra coisa; a última linha do último arquivo pode não ter uma linha \neletrônica anexada. Eu poderia jurar que respondi a essa pergunta antes.
mikeserv
@cuonglm - eu não entendo o que você quer dizer. aquele pedacinho de casca que acabei de lhe dar impressões 1\n2\n3. funciona. sempre faz. o que é impresso para você?
mikeserv
1
@DennisWilliamson: Usar \nem RHS não é padrão. Você pode usar sed -e '$G'.
cuonglm
2

Semelhante à resposta do @terdon , se você preferir também ver o nome do arquivo no futuro, poderá usar o headcomando:

$ head *file*
==> file_1 <==
file 1 content

==> file_2 <==
file 2 content

==> file_3 <==
file 3 content

heado padrão é 10 primeiras linhas, portanto, usá-lo sem opções de comando para o seu caso (uma frase por arquivo) é perfeitamente adequado. Caso contrário, você precisa da -n Xopção.

hjk
fonte
2

Outra maneira - use grep -hpara simplesmente procurar a string vazia em cada arquivo. Isso corresponderá a todas as linhas, independentemente de quantas ou se a nova linha terminou ou não. Os resultados grep são sempre terminados em nova linha. A -hopção suprime o prefixo de cada linha de saída com o nome do arquivo de origem:

$ printf 'a' > a
$ printf 'b\nB' > b
$ printf 'c\n' > c
$ ls
a  b  c
$ cat -- *
ab
Bc
$ grep -h '' *
a
b
B
c
$ 

Ou você pode usar o GNU pasteno -smodo serial com nova linha como delimitador:

$ paste -s -d '\n' -- *
a
b
B
c
$ 
Trauma Digital
fonte