Обновление Добавлена версия для редактирования последнего вопроса.
С Perl (как помечено), используя ваши эхо-строки данных в файле data.txt
perl -wnE'@m = m{^test/([\w-]+)(?=/)}g; say "@m" if @m' data.txt
При этом печатается только alpha_numeric-9034
с первой строки.
Я использую [\w-]
, перейдите к классу POSIX , [[:alnum:]_-]
если хочешь.Другой вариант - перечислить запрещенные символы вместе с /
в отрицательном классе, [^/...]
.
Код захватывает разрешенные символы после ^test/
до следующего /
, используя положительный прогнозутверждать, что /
есть.Происхождение, представляющее собой « утверждение нулевой ширины », не использует этот слеш, иначе это не удастся с более чем двумя слешами.
Предполагая путь в качестве цели, код захватывается между слешамитолько когда что-то есть, отбрасывая //
, но все еще совпадая с линией.Если вы хотите, чтобы «ничего» между косыми чертами, измените квантификатор +
на *
, и вы получите пустую строку для этой пары //
.
Она также работает с любым количеством слешей, извлекаячто находится между последовательными.Протестировано добавлением строки test/first/yet/more/end
в файл, использованный выше, для
alpha_numeric-9034
first yet more
Примечание Последнее редактирование вопроса позволяет test/QR-9034
, поэтому без вторая косая черта.Это противоречит первоначальному утверждению и явным ранним разъяснениям, а решения выше (Perl) и ниже (bash) не были предназначены для него и не будут работать в этом случае.
Однако, это (намного) проще, если мы можем иметь не более двух слешей
perl -wnE'say $1 if m{^test/([\w-]+)/?}' data.txt
Это соответствует тому, что следует ^test/
, как указано выше, до следующего необязательный (?
) косая черта.
Если это действительно касается парсинга путей, пожалуйста, используйте модули, которые делают именно это.
Разъяснено, что цельэто делается в bash с «минимальной поддержкой инструмента / языка» .Тогда это можно сделать прямо в bash.Это не будет кратким, как в Perl, но другие инструменты не используются.В одну сторону
#!/bin/bash
string='test/one/two/end'
# Build array of fields using / for the separator
IFS='/' read -ra ary <<< "$string"
# Note: don't know how the presumed bash script is organized
# Use checks below (or alternatives) for flow control you need
# Check for non :alnum: characters. Iterating is a bit slow but clear
for i in "${ary[@]}"; do
if [[ "$i" =~ [^[:alnum:]] ]]; then
echo "Element $i has non-alnum"
has_special=1
break
fi
done
if [[ ${#ary[@]} -le 1 || ${ary[0]} != "test" || $has_special ]]; then
echo "No match"
else
# Remove first and last elements
unset 'ary[${#ary[@]}-1]'
unset 'ary[${ary[0]}]'
echo "${ary[@]}"
fi
Это печатает строку: one two
(или No match
, если строка / $IFS
изменена так, чтобы потерпеть неудачу)
Все части вышеперечисленного могут бытьсделано другими способами.Комментарии
Проверки (не для alnum, test/
и общего соответствия) даются просто, так как не указано, какое управление потоком подходит.Реструктуризация для лучшей организации программы
Итерация, используемая для проверки элементов массива, ясна, но медленна;Есть и другие способы.Если есть интерес к этому, пожалуйста, дайте мне знать, и я отредактирую.Кроме того, сама строка может быть проверена, но тогда мы не можем (просто) использовать :alnum:
, поскольку она содержит /
read
практически самый эффективный способ разбить строку разделителями на массив, без разветвлений, внешних инструментов или ресурсов
На более новой версии bash (4.3+?) вы можете просто сделать unset 'array[-1]'
etc
В последнем bash вышеуказанные изменения $IFS
только в пределах текущей команды
Если не было совпадений, вся строка находится впервый элемент ary
, поэтому я проверяю размер