у меня есть новости для вас. Вы пишете скрипт Bash, вы являются программистом!
Ваше регулярное выражение (RE) относится к «неправильному» типу. Vanilla grep
использует форму, известную как «Основные регулярные выражения» (BRE), но ваш RE имеет форму расширенного регулярного выражения (ERE). BRE, используются по ванили grep
, vi
, more
и т.д. EREs используется почти все остальное, awk
, Perl
, Python
, Java
, .Net
и т.д. Проблема заключается в том, вы пытаетесь искать этот шаблон в содержимом файл, не в имени файла!
Существует egrep
команда, или вы можете использовать grep -E
, так:
echo $zip|grep -E '^[0-9]\.[0-9]{1,2}\.[0-9]{1,2}$'
(обратите внимание, что одиночные кавычки являются более безопасными, чем в два раза). Кстати, вы используете ^
спереди и $
в конце, что означает, что имя файла ТОЛЬКО состоит из номера версии, но вы говорите, что номер версии «где-то в имени файла». Это не значит, что вам нужен квантификатор .
НО, вы, похоже, не забираете номер версии.
Вы можете использовать sed
(мы также нуждаемся в -E
):
ver=$(echo $zip| sed -E 's/.*([0-9]\.[0-9]{1,2}\.[0-9]{1,2}).*/\1/')
\1
на праве означает «заменить все с тем, что было подобрано в (именно поэтому мы имеем * спереди и сзади). круглые скобки ". Это немного неуклюже, я знаю.
Теперь мы можем сделать mkdir
(не заслуга в класть все на одной линии, и это делает код труднее поддерживать):
mkdir -p "$MODS/out/$ver"
${ver}
ненужно в этом случае, но это хорошая идея заключить имена путей в двойные кавычки, если любой из компонентов имеет встроенное белое пространство.
Итак, хорошее усилие для «не-программиста», особенно при создании этого RE.
Теперь Урок 2
Будьте осторожны при использовании этого решения в общем цикле. В вашем конкретном вопросе используется select
, поэтому мы не можем предсказать, какие файлы будут использоваться. Но что, если мы хотим сделать это за каждый файл?
Использование вышеуказанного решения в цикле for
или while
будет неэффективным. Вызов внешних процессов внутри цикла всегда плох. Мы ничего не можем сделать с mkdir
без использования другого языка, такого как Perl или Python. Но sed
, по своей природе итеративно, и мы должны использовать эту функцию.
Одним из вариантов было бы использовать шаблон раковины, соответствующий вместо sed
. Эта конкретная модель не была бы невозможна в оболочке, но это было бы сложно и вызвать другие вопросы. Поэтому давайте придерживаться sed
.
Проблема заключается в том, что echo
выход помещает пространство между каждым полем. Это дает нам пару вопросов. sed
ограничивает каждую запись новой строкой «\ n», поэтому echo
сам по себе здесь не будет. Мы могли бы заменить каждое пространство новой строкой, но это было бы проблемой, если бы были пробелы внутри имени файла. Мы могли бы сделать некоторые обманки с IFS
и подталкиванием, но это приводит к ненужным осложнениям. Поэтому вместо этого мы вернемся к добрым старым ls
. Как правило, мы не хотели бы использовать ls
, более гибкое чередование оболочки, но здесь мы используем функцию, которая будет размещать новую строку после каждого имени файла (при использовании перенаправленного через канал).
while read ver
do
mkdir "$ver"
done < <(ls $SRC/*.zip|sed -E 's/.*([0-9]{1}\.[0-9]{1,2}\.[0-9]{1,2}).*/\1/')
Здесь я использую процесс замены, и этот цикл будет вызывать только ls
и sed
один раз. НО, он вызывает программу mkdir
n раз.
Lession 3
Извините, но это по-прежнему неэффективны. Мы создаем дочерний процесс для каждой итерации, для создания каталога требуется только один вызов API ядра, но мы создаем для этого только процесс?Давайте используем более сложный язык, такой как Perl:
#!/usr/bin/perl
use warnings;
use strict;
my $SRC = '.';
for my $file (glob("$SRC/*.zip"))
{
$file =~ s/.*([0-9]{1}\.[0-9]{1,2}\.[0-9]{1,2}).*/$1/;
mkdir $file or die "Unable to create $file; $!";
}
Возможно, вы заметили, что ваш RE прошел здесь! Но теперь у нас больше контроля, и никакие дочерние процессы (mkdir
в Perl не являются встроенными, как и glob
).
В заключение, для небольшого количества файлов петля sed
выше будет в порядке. Это просто и оболочка. Вызов Perl только для этого из сценария, вероятно, будет медленнее, так как perl довольно большой. Но скрипты оболочки, которые создают дочерние процессы внутри циклов, не масштабируются. Perl есть.
Aah! После всех моих усилий, я вижу, что мне не хватает самой простой вещи, «echo $ zip», ха-ха! Изучайте каждый день! Я вижу с помощью команды SED, это меняет мое представление о том, как искать строки в файлах, а не использовать grep :) Теперь я напишу свою функцию и закончу код, я отправлю его здесь, чтобы показать результаты! – user1170663
@ user1170663: точка в том, что 'grep' ищет строки в файлах, но это не то, что вы хотели сделать, вы хотели * извлечь * строку из имени файла. Другой. – cdarke
@ user1170663: см. Мои новые изменения. Я боюсь, что боюсь! – cdarke