У меня есть этот маленький скрипт в sh
(Mac OSX 10.6) для просмотра массива файлов. Google перестал быть полезным на этом этапе:
files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done
До сих пор (очевидно, что вы, гуру оболочки) $name
просто держите 0, 1 или 2, в зависимости от того, grep
обнаружено ли, что имя файла соответствует указанному вопросу. То, что я хотел бы, это захватить то, что находится внутри паренов, ([a-z]+)
и сохранить это в переменной .
Я хотел бы использовать grep
только, если это возможно . Если нет, пожалуйста, не используйте Python или Perl и т. Д. sed
Или что-то в этом роде - я новичок в shell и хотел бы атаковать это с точки зрения * nix purist.
Кроме того, как супер крутые бонусы , мне интересно, как я могу объединить строку в оболочке? Была ли захваченная группа строкой «somename», хранящейся в $ name, и я хотел добавить строку «.jpg» в конец, не так ли cat $name '.jpg'
?
Пожалуйста, объясните, что происходит, если у вас есть время.
grep
, тоsed
было бы здорово, если бы можно было решить с помощьюsed
.Ответы:
Если вы используете Bash, вам даже не нужно использовать
grep
:Лучше поместить регулярное выражение в переменную. Некоторые шаблоны не будут работать, если включены буквально.
Используется
=~
оператор Bash для регулярных выражений. Результаты матча сохраняются в массиве с именем$BASH_REMATCH
. Первая группа захвата сохраняется в индексе 1, вторая (если есть) в индексе 2 и т. Д. Индекс ноль - это полное совпадение.Вы должны знать, что без якорей это регулярное выражение (и то, которое использует
grep
) будет соответствовать любому из следующих примеров и более, которые могут не соответствовать тому, что вы ищете:Чтобы исключить второй и четвертый примеры, сделайте свое регулярное выражение следующим образом:
который говорит, что строка должна начинаться с одной или нескольких цифр. Карат представляет начало строки. Если вы добавите знак доллара в конце регулярного выражения, вот так:
тогда третий пример также будет исключен, поскольку точка не находится среди символов в регулярном выражении, а знак доллара представляет конец строки. Обратите внимание, что четвертый пример также не соответствует этому совпадению.
Если у вас есть GNU
grep
(около 2,5 или более поздней версии, я думаю, когда\K
оператор был добавлен):\K
Оператор ( с переменной длиной смотреть-сзади) вызывает предыдущий образец , чтобы соответствовать, но не включает в себя матч в результате. Эквивалент фиксированной длины(?<=)
- шаблон будет включен перед закрывающей скобкой. Вы должны использовать ,\K
если кванторы могут соответствовать строки различной длины (например+
,*
,{2,4}
).В
(?=)
операторе соответствует фиксированному или модели переменной длины и называются «упреждающим». Это также не включает совпавшую строку в результат.Чтобы сделать совпадение без учета регистра, используется
(?i)
оператор. Это влияет на паттерны, которые следуют за ним, поэтому его положение является значительным.Регулярное выражение может потребоваться изменить в зависимости от того, есть ли в имени файла другие символы. Вы заметите, что в этом случае я показываю пример объединения строки в то же время, когда подстрока захвачена.
источник
/K
оператор качается.grep
. Он был также принят ФП и проголосовал довольно много. Спасибо за отрицание.Это не возможно с чистым
grep
, по крайней мере, вообще.Но если ваш шаблон подходит, вы можете использовать его
grep
несколько раз в конвейере, чтобы сначала привести свою строку к известному формату, а затем извлечь нужный бит. (Хотя инструменты, какcut
иsed
гораздо лучше в этом).Предположим, что ваш шаблон немного проще:
[0-9]+_([a-z]+)_
вы можете извлечь это так:Первая
grep
удалит все строки, которые не соответствуют вашему общему шаблону, втораяgrep
(которая--only-matching
указала) будет отображать альфа-часть имени. Это работает только потому, что шаблон подходит: «альфа-часть» достаточно конкретна, чтобы вытянуть то, что вы хотите.(Помимо: лично я бы использовал
grep
+cut
для достижения того, что вы после:.echo $name | grep {pattern} | cut -d _ -f 2
Это позволяетcut
проанализировать строку на поля путем разделения на разделитель_
и возвращает только поле 2 (номера полей начинаются с 1)).Философия Unix состоит в том, чтобы иметь инструменты, которые делают одну вещь, и делают это хорошо, и объединяют их для достижения нетривиальных задач, поэтому я бы сказал, что
grep
+sed
etc - это более Unixy способ делать вещи :-)источник
for f in $files; do name=
echo $ f | grep -oEi '[0-9] + _ ([az] +) _ [0-9a-z] *' | cut -d _ -f 2;
Ага!Я понимаю, что ответ на этот вопрос уже был принят, но с «строго * nix пуристской точки зрения” кажется, что это правильный инструмент для работы
pcregrep
, о котором пока не упоминалось. Попробуйте изменить строки:к следующему:
получить только содержимое группы захвата 1.
pcregrep
Инструмент использует все тот же синтаксис , вы уже использовали сgrep
, но реализует функциональные возможности, которые вам нужно.Параметр
-o
работает так же, какgrep
версия, если он пуст, но он также принимает числовой параметрpcregrep
, который указывает, какую группу захвата вы хотите показать.Благодаря этому решению в сценарии требуется минимум изменений. Вы просто заменяете одну модульную утилиту другой и настраиваете параметры.
Интересное примечание: Вы можете использовать несколько аргументов -o для возврата нескольких групп захвата в порядке их появления в строке.
источник
pcregrep
по умолчанию недоступен, вMac OS X
котором используется OPpcregrep
кажется, не понимает цифру после-o
: «Неизвестная опция буква« 1 »в« -o1 ». Также нет упоминания об этой функциональности при взглядеpcregrep --help
7.8 2008-09-05
.echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
pcregrep
8,41 (устанавливается сapt-get install pcregrep
наUbuntu 16.03
) не распознает-Ei
переключатель. Это работает отлично без этого, все же. В macOS сpcregrep
установленным черезhomebrew
(также 8.41), как упоминалось выше @anishpatel, по крайней мере, в High Sierra-E
коммутатор также не распознается.Не возможно в просто grep я верю
для седа:
Я возьму удар на бонус, хотя:
источник
sed
решение не работает. Он просто распечатывает все в моем каталоге.Это решение, которое использует gawk. Это то, что мне нужно часто использовать, поэтому я создал для него функцию
использовать просто сделать
источник
\s
. Вы знаете, как это исправить?Совет для вас - вы можете использовать расширение параметра, чтобы удалить часть имени из последнего подчеркивания и далее, аналогично в начале:
Тогда
name
будет иметь значениеabc
.См. Документацию Apple для разработчиков , ищите «Расширение параметров».
источник
если у вас есть Bash, вы можете использовать расширенную Globbing
или
источник