Mam ten mały skrypt w sh
(Mac OSX 10.6) do przeglądania szeregu plików. Google przestało być w tym momencie pomocne:
files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done
Do tej pory (oczywiście dla ciebie guru powłoki) $name
zawiera tylko 0, 1 lub 2, w zależności od grep
tego, czy nazwa pliku odpowiada podanej materii. Chciałbym uchwycić to, co jest w parens ([a-z]+)
i zapisać to w zmiennej .
Chciałbym użyć grep
tylko, jeśli to możliwe . Jeśli nie, proszę, nie używaj Pythona, Perla itp. sed
Lub coś podobnego - jestem nowy w powłoce i chciałbym zaatakować to z purystycznego * nix.
Ponadto, jako super fajne bonusy , jestem ciekawy, jak mogę połączyć strunę w skorupce? Czy grupa, którą przechwyciłem, to ciąg „nazwa” przechowywany w $ name, a chciałem dodać ciąg „.jpg” na końcu, prawda cat $name '.jpg'
?
Wyjaśnij, co się dzieje, jeśli masz czas.
grep
,sed
byłoby świetnie, jeśli można rozwiązać za pomocąsed
.Odpowiedzi:
Jeśli używasz Bash, nie musisz nawet używać
grep
:Lepiej umieścić regex w zmiennej. Niektóre wzory nie będą działać, jeśli zostaną dosłownie uwzględnione.
Wykorzystuje
=~
to, który jest operatorem dopasowania wyrażenia regularnego Basha. Wyniki dopasowania są zapisywane w tablicy o nazwie$BASH_REMATCH
. Pierwsza grupa przechwytywania jest przechowywana w indeksie 1, druga (jeśli istnieje) w indeksie 2 itd. Indeks zero jest pełnym dopasowaniem.Należy pamiętać, że bez kotwic, to wyrażenie regularne (i ten używający
grep
) będzie pasować do dowolnego z następujących przykładów i nie tylko, które mogą nie być tym, czego szukasz:Aby wyeliminować drugi i czwarty przykład, wykonaj wyrażenie regularne w ten sposób:
co oznacza, że ciąg musi zaczynać się od jednej lub więcej cyfr. Karat reprezentuje początek łańcucha. Jeśli dodasz znak dolara na końcu wyrażenia regularnego, w ten sposób:
wtedy trzeci przykład również zostanie wyeliminowany, ponieważ kropka nie znajduje się wśród znaków w wyrażeniu regularnym, a znak dolara reprezentuje koniec łańcucha. Zauważ, że czwarty przykład również nie pasuje do tego dopasowania.
Jeśli masz GNU
grep
(około 2,5 lub później, myślę, że kiedy\K
operator został dodany):\K
Uruchamiający (o zmiennej długości wygląd opóźnieniem) powoduje, że powyższy wzór do meczu, ale nie obejmuje dopasowanie w wyniku. Odpowiednikiem o stałej długości jest(?<=)
- wzorzec zostanie dołączony przed nawiasem zamykającym. Należy użyć\K
, jeśli kwantyfikatory mogą dopasować ciągi o różnej długości (na przykład+
,*
,{2,4}
).Te
(?=)
mecze operatora stałej lub zmiennej długości wzory i nazywa się „look-ahead”. Nie zawiera również dopasowanego ciągu w wyniku.Aby uczynić dopasowanie bez rozróżniania wielkości liter,
(?i)
używany jest operator. Wpływa na wzorce, które za nim podążają, więc jego pozycja jest znacząca.Wyrażenie regularne może wymagać dostosowania w zależności od tego, czy w nazwie pliku znajdują się inne znaki. Zauważysz, że w tym przypadku pokazuję przykład konkatenacji łańcucha w tym samym czasie, gdy przechwytywany jest podciąg.
źródło
/K
skały operatora.grep
. Został również zaakceptowany przez PO i dość mocno głosowany. Dzięki za recenzję.Nie jest to tak naprawdę możliwe w przypadku czystego
grep
, przynajmniej ogólnie.Ale jeśli twój wzorzec jest odpowiedni, możesz być w stanie użyć
grep
wiele razy w potoku, aby najpierw zmniejszyć linię do znanego formatu, a następnie wyodrębnić tylko żądany bit. (Chociaż narzędzia takie jakcut
ised
są w tym znacznie lepsze).Załóżmy dla argumentu, że twój wzór był nieco prostszy:
[0-9]+_([a-z]+)_
Możesz to wyodrębnić w następujący sposób:Pierwszy
grep
usunie wszystkie wiersze, które nie pasują do twojego ogólnego patern, drugigrep
(który--only-matching
określił) wyświetli część alfa nazwy. Działa to tylko dlatego, że wzór jest odpowiedni: „część alfa” jest wystarczająco specyficzna, aby wyciągnąć to, co chcesz.(Na bok: osobiście użyłbym
grep
+,cut
aby osiągnąć to, czego szukasz :.echo $name | grep {pattern} | cut -d _ -f 2
Spowodujecut
to przeanalizowanie linii do pól przez podział na separator_
i zwróci tylko pole 2 (numery pól zaczynają się od 1)).Filozofią Uniksa jest posiadanie narzędzi, które wykonują jedną rzecz i robią to dobrze, i łączą je, aby osiągnąć niebanalne zadania, więc twierdzę, że
grep
+sed
etc to bardziej uniksowy sposób robienia rzeczy :-)źródło
for f in $files; do name=
echo $ f | grep -oEi '[0-9] + _ ([az] +) _ [0-9a-z] *' | cut -d _ -f 2;
Aha!Zdaję sobie sprawę, że odpowiedź na to pytanie została już zaakceptowana, ale z „ściśle * purystycznego punktu widzenia” wydaje się, że właściwym narzędziem jest praca
pcregrep
, o której jeszcze nie wspomniano. Spróbuj zmienić linie:do następujących:
aby uzyskać tylko zawartość grupy przechwytywania 1.
pcregrep
Narzędzie wykorzystuje wszystkie z tej samej składni już używane zgrep
, ale implementuje funkcjonalność, czego potrzebujesz.Ten parametr
-o
działa tak jakgrep
wersja, jeśli jest pusty, ale akceptuje również parametr numerycznypcregrep
, który wskazuje, którą grupę przechwytywania chcesz pokazać.Dzięki temu rozwiązaniu w skrypcie jest wymagane minimum zmian. Po prostu zamieniasz jedno narzędzie modułowe na inne i dostosowujesz parametry.
Interesująca uwaga: Możesz użyć wielu argumentów -o, aby zwrócić wiele grup przechwytywania w kolejności, w jakiej pojawiają się w wierszu.
źródło
pcregrep
nie jest domyślnie dostępny, wMac OS X
którym używa POpcregrep
Wydaje mi się, że nie rozumiem cyfry po-o
: „Nieznana litera opcji„ 1 ”w„ -o1 ”. Nie wspomina się też o tej funkcji, patrząc napcregrep --help
7.8 2008-09-05
.echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
pcregrep
8.41 (zainstalowany zapt-get install pcregrep
włączonymUbuntu 16.03
) nie rozpoznaje-Ei
przełącznika. Bez niego jednak działa idealnie. Na macOS, zpcregrep
zainstalowanym przezhomebrew
(także 8.41), jak wspomniano powyżej @anishpatel, przynajmniej w High Sierra-E
przełącznik nie jest rozpoznawany.Uważam, że nie jest to możliwe tylko w grep
dla sed:
Zrobię dźgnięcie premii:
źródło
sed
rozwiązanie nie działa. Po prostu drukuje wszystko w moim katalogu.To rozwiązanie wykorzystuje gawk. Muszę często korzystać z tego, więc stworzyłem dla niego funkcję
użyć po prostu zrób
źródło
\s
. Czy wiesz jak to naprawić?Sugestia dla Ciebie - możesz użyć rozszerzenia parametrów, aby usunąć część nazwy od ostatniego podkreślenia i podobnie na początku:
Wtedy
name
będzie miał wartośćabc
.Zobacz dokumenty programistów Apple , wyszukaj „Rozszerzenie parametrów”.
źródło
jeśli masz bash, możesz użyć rozszerzonego globowania
lub
źródło