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?

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.


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

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 )


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 *

@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.


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
$ 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.