espansione della shell (A | B) nei nomi dei file?


9

È possibile espandere una orscelta nella shell durante la lettura di un file, ad esempio.

Ciò che intendo con questo è che, ad esempio, grepsupporta la sintassi come la (A|B)corrispondenza di A o B in un file.

Allo stesso modo, se ho questi file:

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

Ho potuto fare cat file{1..5}.txta bash, mentre si espande la gamma. Esiste un modo equivalente per farlo solo per un paio di file?

Ad esempio cat file(1|5).txte stampare solo quei 2?

Risposte:


16

Il modello di globbing del nome file standard per abbinare una cifra è [0-9]. Questo corrisponde a una singola cifra:

cat file[0-9].txt

Per selezionare solo due di questi:

cat file[25].txt

Per numeri maggiori di 9, l'espansione del controvento sarà utile (ma vedi la nota sotto per la differenza tra schemi di globbing ed espansioni del controvento):

cat file{25..60}.txt

Ancora una volta, l'espansione del controvento consente anche i singoli numeri:

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

(si noti che nell'esempio sopra, l'espansione del controvento non comporta un ciclo aritmetico, ma genera semplicemente nomi basati sulle stringhe fornite).

In bash, con l' extglobopzione shell abilitata ( shopt -s extglob), funzionerà anche:

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

Lo @(...)schema corrisponderà a uno qualsiasi degli |schemi inclusi -dimitati.


La differenza tra i modelli globbing come [...]e @(...)ed espansioni bretelle, è che un espansione delle parentesi graffe viene generato sulla riga di comando e non può effettivamente corrispondere eventuali nomi esistenti nella directory corrente. Un modello globbing di nome file corrisponderà ai nomi, ma la shell non si lamenterà se non esiste un nome possibile. Se non esiste un nome corrispondente, il modello rimarrà non espanso, a meno che non nullglobsia impostata anche l' opzione shell, nel qual caso il motivo viene rimosso.

Esempio:

touch file1

ls file[0-9]

Qui, file1verrà mostrato solo l'elenco dei file per .

Con ls file{0..9}, lssi lamenterebbe di non aver trovato file0, file2ecc.

Nel seguente esempio, il primo comando toccherà solo i nomi esistenti che corrispondono al modello dato, mentre la seconda riga creerà file che non esistono già:

touch file[0-9]

touch file{0..9}

@thecarpy Mi dispiace, ma questo non è uno schema che corrisponderebbe ad es file45.txt. L'espressione parentesi [...]funziona esattamente come nell'espressione regolare ma viene utilizzata !al posto di ^per dire "non in". Un [...]modello corrisponderà sempre a un singolo carattere.
Kusalananda

Hai ragione! A proposito, anche il mio {1,2}non è conforme a POSIX ... ho imparato alcune cose nuove oggi!
giovedì

2
Il fatto che le espansioni di parentesi graffe non debbano necessariamente corrispondere a file reali può essere estremamente utile, se lo si utilizza per (ad esempio) generare modelli a cui passare grep, generare URL a cui passare curle così via ... ma può anche essere fonte di confusione alle persone che sono abituate a lavorare con i globs.
Kevin,

@Kevin Correct. Un'espansione di parentesi graffe non deve necessariamente riguardare nomi di file.
Kusalananda

7

La sintassi da utilizzare è quella file{1,2}che valuterà file1e file2.

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

Come Inian ha sottolineato anche di seguito ... sarebbe più facile fare touch file{1..9}in questo caso di esempio ...

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

Puoi anche utilizzare più espressioni, come:

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

Sì, quanto sopra creerà 234 ( 9volte 26) file.


1
Questa file{1,2} sintassi è anche comoda per rinominare i file:mv some_very_long_filename.txt{,.bak}
Eric Duminil,

6

Sì, puoi usare l'espansione del controvento nella bashshell. Solo per un paio di file, fai file{1..2}o semplicementefile{1,2}

O se sei preoccupato che i file non siano presenti in alcuni casi, fai un semplice ciclo,

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

O se la semplice concatenazione è la tua unica operazione sui file e se non sei sicuro di quali file non possano essere presenti in qualsiasi momento, basta semplicemente cateliminarli. Ri-indirizzare l'errore standard per /dev/nulleliminare gli errori se il file non è disponibile.

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

oppure usa l'espressione glob file[15]che non si lamenta degli errori se il file non è stato trovato.

cat file[15].txt

2
No, nessuna preoccupazione sul fatto che i file non siano presenti, volevo solo mostrare il contenuto di 2 file numerati numericamente, ma che non sono consecutivi, quindi la file{1,5}sintassi della virgola era tutto ciò che mi mancava!
Joe Healey,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.