expansão de shell (A | B) em nomes de arquivos?

9

É possível expandir uma opção or no shell ao ler um arquivo, por exemplo.

O que quero dizer com isso é que, por exemplo, grep suporta sintaxe como (A|B) para corresponder A ou B em um arquivo.

Da mesma forma, se eu tiver esses arquivos:

file1.txt
file2.txt
file3.txt
file4.txt
file5.txt

Eu poderia fazer cat file{1..5}.txt em bash , pois ele expande o intervalo. Existe uma maneira equivalente de fazer isso por apenas alguns arquivos?

Por exemplo cat file(1|5).txt e apenas imprime os 2?

    
por Joe Healey 11.02.2018 / 14:00

3 respostas

16

O padrão de globbing do nome de arquivo padrão para corresponder a um dígito é [0-9] . Isso corresponde a um único dígito:

cat file[0-9].txt

Para selecionar apenas dois deles:

cat file[25].txt

Para números maiores que 9, a expansão de chaves será útil (mas veja a nota abaixo para a diferença entre padrões de globbing e expansões de chaves):

cat file{25..60}.txt

Novamente, a expansão de chaves também permite números individuais:

cat file{12,45,900,xyz}.txt

(note que no exemplo acima, a expansão da chave não envolve um loop aritmético, mas apenas gera nomes baseados nas strings fornecidas).

Em bash , com a opção extglob do shell ativada ( shopt -s extglob ), o seguinte também funcionará:

cat file@(12|45|490|foo).txt

O padrão @(...) corresponderá a qualquer um dos padrões incluídos | -delimited.

A diferença entre os padrões globbing como [...] e @(...) e expansões de chaves, é que uma expansão de chave é gerada na linha de comando e pode não corresponder realmente a nenhum nome existente no diretório atual. . Um padrão de agrupamento de nomes de arquivos corresponderá aos nomes, mas o shell não irá reclamar se nem todos os nomes possíveis existirem. Se nenhum nome correspondente existir, o padrão permanecerá não expandido, a menos que também a opção nullglob shell esteja definida, caso em que o padrão é removido.

Exemplo:

touch file1

ls file[0-9]

Aqui, apenas a listagem de arquivos para file1 será mostrada.

Com ls file{0..9} , ls reclamaria por não encontrar file0 , file2 etc.

No exemplo a seguir, o primeiro comando só tocará em nomes existentes que correspondem ao padrão dado, enquanto a segunda linha criará arquivos que ainda não existem:

touch file[0-9]

touch file{0..9}
    
por 11.02.2018 / 14:10
7

A sintaxe a usar é file{1,2} , que será avaliada como file1 e file2 .

$ ls
$ touch file{1,2,3,4,5,6,7,8,9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Como Inian apontou abaixo também ... seria mais fácil fazer touch file{1..9} neste exemplo ...

$ ls
$ touch file{1..9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Você também pode usar várias expressões, como:

$ ls
$ touch file{1..9}{a..z}
$ ls
file1a file1b file1c
[...]
file9x file9y file9z

Sim, os itens acima criarão 234 arquivos ( 9 times 26 ).

    
por 11.02.2018 / 14:02
6

Sim, você pode usar a expansão de chaves no shell bash . Para apenas alguns arquivos, basta fazer file{1..2} ou apenas file{1,2}

Ou se você estiver preocupado com o fato de os arquivos não estarem lá em alguns casos, basta fazer um loop simples,

for file in file{1..4}.txt; do
    [ -f "$file" ] || continue
    echo "$file" # Do other actions on file here
done

Ou se apenas concatenar for sua única operação nos arquivos e se você estiver inseguro sobre quais arquivos não podem estar presentes a qualquer momento, apenas cat e suprime os erros. O redirecionamento do erro padrão para /dev/null suprimiria os erros se o arquivo não estivesse disponível.

cat file{1,5}.txt 2>/dev/null

ou use a expressão glob file[15] que não reclama dos erros se o arquivo não foi encontrado.

cat file[15].txt
    
por 11.02.2018 / 14:02