Como ordenar nomes de arquivos com espaços neles e concatenar os arquivos?

2

Eu tenho a infelicidade de lidar com nomes de arquivos que contêm espaços. Eu quero concatenar arquivos dos quais nomes de arquivos contêm espaços. Eu também quero classificar os nomes de arquivos numericamente. Obviamente, o seguinte falha:

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

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

    
por rightfold 17.11.2014 / 11:11

3 respostas

7

Não há necessidade de ls aqui. É o shell que lista o conteúdo do diretório expandindo o *.sql glob.

Em um sistema GNU ou FreeBSD:

printf '%s
cat ./*.sql(.n)
' *.sql | sort -nz | xargs -r0 cat --

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

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

Ou se você tiver n :

printf '%s
cat ./*.sql(.n)
' *.sql | sort -nz | xargs -r0 cat --

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

    
por 17.11.2014 / 12:15
1

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

Não há nada de errado com as outras respostas, mas isso pode ser uma resposta mais direta a como lidar com espaços em geral e esta resposta introduz 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 o IFS. link $ IFS. Acho que aprendi sobre isso há muito tempo lendo o livro BASH de O'Rielly.

    
por 17.11.2014 / 12:42
1

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

ls -1d -- *.sql | sort -n | xargs -d "\n" cat --
    
por 17.11.2014 / 11:25