rozszerzenie powłoki (A | B) w nazwach plików?

9

Czy można na przykład rozszerzyć orwybór w powłoce podczas odczytu pliku?

Rozumiem przez to, że na przykład grepobsługuje składnię, taką jak (A|B)dopasowanie A lub B w pliku.

Podobnie, jeśli mam te pliki:

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

Mogłem zrobić cat file{1..5}.txtw bash, ponieważ rozszerza zakres. Czy istnieje równoważny sposób na zrobienie tego tylko dla kilku plików?

Np. cat file(1|5).txtI wydrukuj tylko te 2?

Joe Healey
źródło

Odpowiedzi:

16

Standardowym wzorcem globowania nazw plików pasującym do cyfry jest [0-9]. To pasuje do jednej cyfry:

cat file[0-9].txt

Aby wybrać tylko dwa z nich:

cat file[25].txt

W przypadku liczb większych niż 9 przydatne będzie rozwinięcie nawiasu klamrowego (ale patrz uwaga poniżej na temat różnicy między wzorcami globowania a rozszerzeniami nawiasów):

cat file{25..60}.txt

Ponownie rozwinięcie nawiasu pozwala również na indywidualne liczby:

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

(zauważ, że w powyższym przykładzie interpretacja nawiasów nie obejmuje pętli arytmetycznej, a jedynie generuje nazwy na podstawie podanych ciągów).

W bash, z extglobwłączoną opcją powłoki ( shopt -s extglob), będą również działać:

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

@(...)Wzór będzie pasował do dowolnego jednego z dołączonych |-delimited wzorów.


Różnica między wzorcami globowania jako [...]i @(...)rozszerzeniami nawiasów polega na tym, że rozwinięcie nawiasów jest generowane w wierszu poleceń i może nie pasować do żadnych istniejących nazw w bieżącym katalogu. Wzorzec globowania nazw plików będzie pasował do nazw, ale powłoka nie będzie narzekać, jeśli nie wszystkie możliwe nazwy będą istnieć. Jeśli nie istnieje pasująca nazwa, wzorzec pozostanie nierozwinięty, chyba że zostanie również ustawiona nullglobopcja powłoki, w którym to przypadku wzór zostanie usunięty.

Przykład:

touch file1

ls file[0-9]

Tutaj wyświetlana będzie tylko lista plików dla file1.

Dzięki ls file{0..9}, lsże narzekają nie znalezienia file0, file2etc.

W poniższym przykładzie pierwsze polecenie dotknie tylko istniejących nazw, które pasują do danego wzorca, podczas gdy drugi wiersz utworzy pliki, które jeszcze nie istnieją:

touch file[0-9]

touch file{0..9}
Kusalananda
źródło
@ thehecarpy Przykro mi, ale to nie jest wzór, który pasowałby np file45.txt. Wyrażenie w nawiasach [...]działa tak samo jak w wyrażeniach regularnych, ale używa !zamiast wyrażenia ^„nie w”. [...]Wzór zawsze będzie pasował do pojedynczego znaku.
Kusalananda
Masz rację! BTW, mój też {1,2}nie jest zgodny z POSIX ... nauczyłem się dziś kilku nowych rzeczy!
thecarpy
2
Fakt, że rozszerzenia nawiasów klamrowych nie muszą pasować do rzeczywistych plików, może być niezwykle użyteczny, jeśli używasz go (na przykład) do generowania wzorców do przekazania grep, generowania adresów URL do przesłania curlitp., Ale może to również być mylące dla ludzi przyzwyczajonych do pracy z globami.
Kevin
@Kevin Correct. Rozszerzenie nawiasu klamrowego nie musi dotyczyć nazw plików.
Kusalananda
7

Składnia, której należy użyć, file{1,2}będzie oceniać do file1i file2.

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

Jak wskazał również Inian ... łatwiej byłoby to zrobić touch file{1..9}w tym przykładzie ...

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

Możesz także użyć wielu wyrażeń, takich jak:

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

Tak, powyższe spowoduje utworzenie 234 ( 9razy 26) plików.

karp
źródło
1
Ta file{1,2} składnia jest również wygodna do zmiany nazw plików:mv some_very_long_filename.txt{,.bak}
Eric Duminil
6

Tak, możesz użyć rozszerzenia nawiasu klamrowego w bashpowłoce. Tylko kilka plików po prostu zrób file{1..2}lub tak samofile{1,2}

Lub jeśli martwisz się, że w niektórych przypadkach nie ma tam plików, po prostu wykonaj prostą pętlę,

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

Lub jeśli tylko łączenie jest twoją jedyną operacją na plikach i jeśli nie masz pewności, które pliki nie mogą być obecne w dowolnym momencie, po prostu catje i pomiń błędy. Przekierowanie standardowego błędu w celu /dev/nullwyeliminowania błędów, jeśli plik nie jest dostępny.

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

lub użyj wyrażenia glob, file[15]które nie skarży się na błędy, jeśli plik nie został znaleziony.

cat file[15].txt
Inian
źródło
2
Nie, nie ma obaw, że nie ma tam plików, chciałem tylko pokazać zawartość 2 plików numerowanych numerycznie, ale nie są one następujące po sobie, więc file{1,5}brakowało mi składni przecinków!
Joe Healey