"$@"
делает то же самое с позиционными параметрами, что "${foo[@]}"
делает с переменной-массивом foo
. Как сказал Стивен, вы можете использовать @
в расширениях, которые берут фигурные скобки, например. обозначение среза "${@:1:2}"
будет таким же, как "$1" "$2"
. (Отсутствие второго числа расширяет остальную часть списка, например. "${@:2}"
расширяется до "$2"
и всех позиционных параметров после этого.)
Это соответствует именованным переменным, здесь«имя» специального параметра — @
, а $
впереди просто запускает расширение. Обратите внимание, что фигурные скобки необязательны для простого раскрытия (без индексации или манипуляций со строками внутри ). Итак, "${@}"
— это то же самое, что и "$@"
, и вы могли бы даже написать "${@:1}"
с тем же эффектом, поскольку индексация @
начинается с единицы, а не с нуля.
Но вы не можете использовать ${@[@]}
или ${@[1]}
. Это просто $@
и $1
соответственно. (В некотором смысле $@
уже похож на ${args[@]}
, поэтому вы не можете индексировать его дальше. )Это также означает, что если вы хотите проиндексировать позиционные параметры, вам нужно будет использовать расширение среза, например. ${@:i:1}
чтобы получить элемент в позиции i .
Тем не менее, обратите внимание, что строки -для манипуляций с массивами или @
применяются ко всем элементам по отдельности. Например. здесь oo
удален из foo
и из oo
, но остался третий элемент @
, он просто пустой:
$ set -- foo bar oo
$ printf ":%s:\n" "${@/oo}"
:f:
:bar:
::
Если вы действительно хотите удалить элемент, вам придется сделать что-то еще, например перебрать значения и удалить ненужное. Вероятно, это проще сделать с помощью именованного массива, чем пытаться сделать это только внутри $@
. Скажем, что-то вроде этого:
a=();
for x in "$@"; do
if [[ $x != oo ]]; then
a+=("$x");
fi;
done
Или любой из (намного лучших )ответов на этот вопрос:Как удалить позиционный параметр из $@
Если у вас есть awk, который позволяет использовать расширенные регулярные выражения для разделителя полей, вы можете сделать что-то вроде
$ awk '
BEGIN{FS=""; while((getline < "delim") > 0){FS = FS=="" ? $0 : FS"|"$0}}
NF>1 {for(i=1;i<=NF;i++) print $i}
' names
Abdel
Aziz
Abdel
Piza
Märie
Pierre
ПРИМЕЧАНИЕ. :возможно, было бы чище использовать набор символов [ '+-]
, а не чередование регулярных выражений |'|+|-
(, а также устранило бы возможную путаницу в отношении того, является ли +
литералом или квантором регулярного выражения ). Однако это потребует тщательной перетасовки записей, поскольку -
внутри [...]
является оператором диапазона, если только он не находится ни в начале, ни в конце.
Использование grep
, tr
иsort
:
Предостережение :Нам нужно переместить -
в delims
вверх или вниз файла (или tr
будет думать, что есть диапазон ).
Получить все строки, содержащие символы-разделители, с помощью grep
и заменить все разделители на новые строки (получить все символы в delims
без новых строк с помощьюtr -d '\n' < delims
).
Передайте результат на sort -u
, чтобы исключить дубликаты и перенаправить вывод на compounds
.
grep -F -f delims names | tr -- "$(tr -d '\n' < delims)" '\n' | sort -u > compounds
Выход:
$ cat compounds
Abdel
Aziz
Märie
Pierre
Piza
Сначала мы создаем регулярное выражение на лету с помощью функции quotemeta, которая заключает в кавычки все специальные символы, а затем соединяем их с помощью регулярного выражения ИЛИ |
. Мы пропускаем все строки в именах, которые не содержат хотя бы один элемент из регулярного выражения. В остальном мы разделяем их на регулярное выражение, а затем печатаем только уникальный элемент по одному в строке.
$ perl -lne '
$re //= join "|", map { chomp;quotemeta; } <STDIN>;
next unless /$re/;
print for grep { ! $seen{$_}++ } split /$re/;
' names < delims
Abdel
Aziz
Piza
Märie
Pierre
Можно еще....
awk 'BEGIN{OFS=RS="";FS="\n"; getline;$1=$1;
s=gsub("-","",$0);FS="["$0((s>0)?"-":"")"]";
OFS=RS="\n"}
NF>1{$1=$1; print}' delims names
Abdel
Aziz
Abdel
Piza
Märie
Pierre
Который устанавливает RS
и FS
так, чтобы getline
читал delims
как один $0
, а затем перекомпоновывает его с $1=$1
, убеждаясь, что OFS=""
не добавляет никаких непреднамеренных пробелов.
Затем мы можем немного повозиться gsub
-покер с $0
, чтобы убедиться, что -
происходит только в конце набора символов (только добавление -
в конец FS
] если gsub
успешно и s>0
), чтобы дать вам набор символов [ '+-]
как FS
.
Теперь мы можем установить RS
обратно на \n
, но мы также устанавливаем OFS
на \n
.
Тогда все будет как обычно, где бы NF>1
но поскольку OFS="\n"
нам не нужно перебирать NF
, мы можем просто перекомпоновать с $1=$1
иprint
Вот еще один способ решить задачу pbm. Сначала мы динамически подготавливаем регулярное выражение для выбора строки, заключая каждый символ в квадратные скобки (классы символов ). Таким образом, нет необходимости ставить тире в специально отведенном месте.
re=$(paste -d '[]' /dev/null delims /dev/null | paste -sd '|')
dlm=$(paste -sd\| delims | sed -e 's/||/\n/;s/|//g;s/\n/|/;s:/:\\&:')
rpl=$(printf '\\n%.0s' $(seq ${#dlm}))
sed -En \
-e "/$re/ y/$dlm/$rpl/" \
-e '/\n/p' \
names | sort -u
Abdel
Aziz
Märie
Pierre
Piza
Это будет надежно и переносимо работать для 4 символов в вашем примере:
$ cat tst.awk
NR==FNR {
FS = (NR > 1 ? FS "|" : "") "[" $0 "]"
next
}
NF > 1 {
for ( i=1; i<=NF; i++ ) {
if ( !seen[$i]++ ) {
print $i
}
}
}
.
$ awk -f tst.awk delims names
Abdel
Aziz
Piza
Märie
Pierre
Требуемая здесь сложность заключается в том, что у вас есть 3 метасимвола в вашем наборе из 4 разделителей:
" "
что означает «любая последовательность пробелов» в ФС, "+"
что означает «1 или более повторений предыдущего выражения» в регулярном выражении (undefined, если оно находится в начале регулярного выражения или следует за |
), и "-"
что означает «диапазон», если он находится внутри выражения в квадратных скобках, а не в первом или последнем символе. Таким образом, вы не можете просто создать|
-разделенный список, например |-|+|'
, из символов в разделителях, поскольку тогда значение +
не определено, а значение <blank>
, если бы оно было само по себе, не было бы литерал, и вы не можете включить их все в квадратное выражение [ -+']
, так как тогда значение -
представляет собой диапазон символов от <blank>
до +
, опять же не буквальный.
То, что я делаю выше, — это создание|
-разделенного списка выражений в квадратных скобках [ ]|[-]|[+]|[']
, так как это будет работать для любых/всех символов, которые могут содержаться в разделителях.