Como classificar nomes de arquivos com espaços e concatenar os arquivos?

Como classificar nomes de arquivos com espaços e concatenar os arquivos?

Tenho a infelicidade de lidar com nomes de arquivos que contêm espaços. Quero concatenar arquivos cujos nomes de arquivos contenham espaços. Também quero classificar os nomes dos arquivos numericamente. Obviamente o seguinte falha:

cat $(ls *.sql | sort -n)

desde foo bar.sqlé passado como dois argumentos para cat. Qual é a abordagem usual aqui?

Responder1

Não há necessidade lsaqui. É o shell que lista o conteúdo do diretório expandindo o *.sqlglob.

Em um sistema GNU ou FreeBSD:

printf '%s\0' *.sql | sort -nz | xargs -r0 cat --

(usar \0em vez de \njunto com -z/-0garante que também funcione com nomes de arquivos contendo caracteres de nova linha).

Observe que a classificação numérica -nassume que o número está no início do nome do arquivo.

Ou se você tiver zsh:

cat ./*.sql(.n)

(O nqualificador glob serve para habilitar a classificação numérica (também funciona quando o número não está no início, desde que todos os nomes de arquivo tenham o mesmo prefixo (como file12.sql, file2.sql). Eu adicionei .também para incluir apenas arquivos regulares. Adicione Dse você também quiser arquivos ocultos como .foo.sql).

Responder2

Você pode fazer isso cat $(ls -1)se substituir o IFS. IFS é a variável shell que informa ao BASH quais caracteres usar como delimitador. O valor padrão para IFS é espaço, tabulação, nova linha. Se você alterar o IFS para apenas nova linha, poderá fazer isso cat $(ls -1).

Não há nada de errado com as outras respostas, mas esta pode ser uma resposta mais direta sobre como lidar com espaços em geral e esta resposta apresenta a variável IFS com a qual a maioria não está familiarizada.

#!/bin/bash
dir=$(mktemp -d)
for x in $(seq 10); do
    echo $x > "$dir/$(date) $x.txt"
done

pushd $dir
ls -1 $dir

# Set IFS to newline only inorder to deal with the spaces in the file names
#
oldIFS=$IFS
IFS=$'\n'


cat $(ls -1 $dir)


IFS=$oldIFS

Saída

[sri@localhost test]$ ./test
/tmp/tmp.IuXCBzbTLj ~/test
Mon Nov 17 06:38:52 EST 2014 10.txt
Mon Nov 17 06:38:52 EST 2014 1.txt
Mon Nov 17 06:38:52 EST 2014 2.txt
Mon Nov 17 06:38:52 EST 2014 3.txt
Mon Nov 17 06:38:52 EST 2014 4.txt
Mon Nov 17 06:38:52 EST 2014 5.txt
Mon Nov 17 06:38:52 EST 2014 6.txt
Mon Nov 17 06:38:52 EST 2014 7.txt
Mon Nov 17 06:38:52 EST 2014 8.txt
Mon Nov 17 06:38:52 EST 2014 9.txt
10
1
2
3
4
5
6
7
8
9

Aqui está um link para alguma documentação sobre IFS. http://bash.cyberciti.biz/guide/$IFS. Acho que aprendi sobre isso há muito tempo, lendo o livro BASH de O'Rielly.

Responder3

Use xargs(assumindo a implementação GNU) com um delimitador personalizado (assumindo que os nomes dos arquivos não contenham novas linhas):

ls -1d -- *.sql | sort -n | xargs -d "\n" cat --

informação relacionada