Стандартной командой для применения регулярных выражений к строковым аргументам является expr
с оператором :
. Он понимает стандартные основные регулярные выражения . Он выводит 1 или 0 в зависимости от того, соответствует ли регулярное выражение или нет, если регулярное выражение не имеет хотя бы одной группы захвата, и в этом случае он выводит то, что было сопоставлено первой группой захвата. Одной из особенностей expr
в :
является то, что регулярное выражение неявно привязывается к началу, как если бы оно начиналось с ^
. Так:
text=1234
expr "x$text" : "x.\(.*\)"
Мы добавляем префиксx
(к произвольному )как к тексту, так и к регулярному выражению, иначе команда завершится ошибкой, если содержимое $text
окажется оператором expr
.
Первый .
соответствует первому символу $text
, который не выводится, так как он не входит в группу захвата. Затем мы фиксируем остальные .*
, состоящие из 0 или более символов, столько, сколько возможно для вывода.
Статус выхода будет не -нулевым, если регулярное выражение не соответствует($text
пусто или начинается с чего-то, что не может быть интерпретировано как символ )или если вывод представляет собой число0
(и в зависимости от реализации expr
, некоторые из его различных вариантов написания, такие как 00
, -0
...)или пустая строка.
Но в любом случае вам не нужно запускать expr
или использовать для этого регулярные выражения. Это могут сделать стандартные операторы раскрытия параметров оболочки :
text=1234
printf '%s\n' "${text#?}"
Где ${var#pattern}
расширяется до содержимого $var
, где начальная часть, соответствующая pattern
, была удалена.
Это происходит потому, что он оценивается как несколько аргументов, а не только один. Попробуйте это:
ls "$@"
$@
заменяет все параметры строками, разделенными пробелами.
Например.sh:
#!/usr/bin/env bash
FILE_PATTERN="$1"
MATCHING_FILES=$(eval "echo $FILE_PATTERN")
echo "Files: $MATCHING_FILES"
ls -l $MATCHING_FILES
Это будет использовать первый аргумент для example.sh в качестве шаблона глобуса оболочки. Это, вероятно, сломается для имен файлов, содержащих пробелы или специальные символы. Как переменные должны заключаться в кавычки, чтобы избежать этого, но при этом применять шаблон, вам предстоит узнать.
Использование:
$./example.sh 'file-{x,y}.txt'
Files: file-x.txt file-y.txt
-rw-r--r-- 1 user group 0 30 Sep 16:47 file-x.txt
-rw-r--r-- 1 user group 0 30 Sep 16:47 file-y.txt
Если это вообще возможно, было бы лучше не делать это и вместо этого принимать несколько имен файлов в качестве аргументов. Это, безусловно, сделало бы цитирование переменных более ясным и простым, и вы могли бы избежать вопроса, заданного Стефаном об именах файлов, которые выглядят как шаблоны глобусов.
Я бы сделал:
#! /bin/bash -
sources=()
while getopts d:... o; do
case $o in
(d) sources+=("$OPTARG");;
(...) ;;
esac
done
shift "$((OPTIND - 1))"
ls -- "${sources[@]}"
То есть пусть ваш сценарий принимает список каталогов, где вызывающая сторона использует по одному -d
для каждого каталога.
Затем пользователь может:
my-script -d/home/{x,y}
, если их оболочка поддерживает раскрытие фигурных скобок, или что-то еще, что их оболочка предлагает для облегчения создания этого списка.
В rc
/ fish
/ zsh -o rcexpandparam
это может быть:
my-script -d$array
например (также -d$^array
без rcexpandparam
вzsh
)
Вzsh
:
my-script /home/*(P[-d])
и т. д.
Чтобы ваш сценарий выполнял расширение скобок для аргумента, а не другие формы расширения, вы можете заключать в кавычки все последовательности символов, кроме {
, }
,,
(и .0-9
, если хотите разрешить {1..10}
стили )и прогоняем их через eval
.
Было бы проще с zsh
или ksh93
, так как bash
${var//pattern/replacement}
очень ограничен:
#! /bin/zsh -
source=${1?}
set -o extendedglob
eval "sources=( ${source//(#m)[^"{}".,0-9]##/'$MATCH'} )"
printf ' - "%s"\n' "$sources[@]"
Пример:
$ myscript 'x\{1..3}$$`{a b,c}'
- "x\1$$`a b"
- "x\1$$`c"
- "x\2$$`a b"
- "x\2$$`c"
- "x\3$$`a b"
- "x\3$$`c"
Но тогда пользователь больше не сможет передавать буквальный foo{a,b}
аргумент.
Обычный способ сделать это — передать каталоги в качестве основных аргументов командной строки, не требуя флагов опций. т.е. пользователь запустит my-script -a -b foo /home/me/dir1 /some/other/path
. После запуска getopts
для анализа параметров у вас останутся каталоги в позиционных параметрах, и вы можете просто запустить ls "$@"
. Здесь пользователь может использовать любые расширения, которые позволяет его оболочка, для заполнения этих последних аргументов, будь то /some/path/{foo,bar}
или /some/path/*
.
В качестве альтернативы пользователь может передать несколько параметров -d
, чтобы они выполняли my-script -a -b foo -d /home/me/dir1 -d /some/other/path
. Здесь сложнее использовать расширения, так как им нужно будет добавлять -d
перед каждым аргументом с тем, что позволяет их оболочка. Возможно, с чем-то вроде a=(/path/{this,that}); my-script -a -b foo "${a[@]/#/-d}"
.
В любом случае, копирование расширений оболочки в скрипте не является обычным делом и может застать ваших пользователей врасплох, поэтому я бы не советовал этого делать. Если вы сделаете это, вам также нужно будет решить , какие расширения поддерживать. Не все оболочки поддерживают все расширения, и не все пользователи знают обо всех расширениях, поддерживаемых каждой оболочкой.