Экспортировать значение через среду, а затем расширить его во внутренней оболочке. Предполагая, что оболочка входа username
- Bourne -как¹:
$ export path_value=/home/username/filename\$1.class
$ su username -c 'echo "$path_value"'
/home/username/filename$1.class
Это будет работать, даже если переменная содержит кавычки, но не будет работать, если используемая команда очищает среду. Я не думаю, что su
должен это делать, но sudo
может.
Если мы знаем, что переменная не может содержать одинарные кавычки², то достаточно -одинарного цитирования расширенной строки во внутренней оболочке:
$ path_value=/home/username/filename\$1.class
$ su username -c "echo '$path_value'"
/home/username/filename$1.class
(Обратите внимание, что кавычки стоят в обратном порядке.)
¹ если оболочка входа username
csh
или tcsh
, замените echo "$path_value"
на echo $path_value:q
; если это rc
или производная, с echo $path_value
.
² и символы новой строки, если оболочка входа пользователя — csh
или tcsh
, и что она не содержит байтов, не образующих допустимых символов, если оболочка входа пользователя — yash
. Также имейте в виду, что аргументы, начинающиеся с -
или содержащие обратную косую черту, будут проблемой с echo
, лучше использовать printf '%s\n'
для произвольных данных
В оболочке zsh
:
array=(1 2 3 4 3 3)
if (($#array != ${#${(u)array}})); then
print -u2 array contains duplicates
exit 1
fi
Где ${(u)array}
расширяется до уникальных элементов массива, поэтому мы просто сравниваем количество элементов с количеством уникальных элементов.
Оболочка bash
не имеет эквивалента, но поскольку ее массивы в любом случае не могут содержать байты NUL, если вы работаете в системе GNU, вы можете сделать что-то вроде:
readarray -td '' dups < <(
(( ${#array[@]} == 0 )) ||
printf '%s\0' "${array[@]}" |
LC_ALL=C sort -z |
LC_ALL=C uniq -zd
)
if ((${#dups[@]} > 0)); then
echo >&2 "array has duplicates:"
printf >&2 ' - "%s"\n' "${dups[@]}"
exit 1
fi
В них элементы считаются дубликатами , если они идентичны по байтам -по -байтам, а не в том случае, если их числовые значения совпадают (1
, 01
, 0x1
. ], 1e0
, 2-1
, $'1\n'
, ' 1'
считаются разными ).
Предполагая, что arr
содержит только целые числа и что числа, дополненные нулями, следует считать дубликатами (например, 01
является дубликатом 1
), мы можем использовать второй массив, чтобы сохранить значения, уже "видимые", когда разбор каждого элемента первого массива arr
.
#!/bin/bash
arr=(1 2 3 4 3 3)
seen=()
for i in "${arr[@]}"; do
#Remove padding zeroes, if any
i=$((10#$i))
# If element of arr is not in seen, add it as a key to seen
if [ -z "${seen[i]}" ]; then
seen[i]=1
else
echo "Array contains a duplicate."
break
fi
done
Предполагая, что ваш key_array
массив всегда содержит только целые числа (положительные целые числа ), мы можем использовать тот факт, что обычные массивы разрежены в оболочке bash
. Следующий код перебирает массив ключей, создавая экземпляры элементов в обычном массиве, пока мы не найдем ключ, который мы уже обработали:
key_array=( '09' 1 2 3 4 3 3 '04' '001' '07' )
has_dupes () (
unset -v a
for key do
${a[10#$key]+'return'} # execute "return" if a[10#$key] is set
a[10#$key]= # set a[10#$key] to empty string
done
return 1
)
if has_dupes "${key_array[@]}"; then
echo 'array has dupes'
else
echo 'array has no dupes'
fi
Это вводит вспомогательную функцию has_dupes
, которая принимает список целых чисел и возвращает ноль, если в списке есть повторяющееся значение, и не -ноль, если повторяющихся значений нет.
Расширение стандартного параметра ${variable+word}
используется для вставки слова return
, если ранее было установлено a[10#$key]
. При подстановке return
выполнение функции прекращается, и вызывающему объекту возвращается нулевой статус выхода, означающий, что мы нашли повторяющееся значение. Индекс 10#$key
означает «значение $key
, интерпретируемое как целое число с основанием 10» и позволяет нам приравнять такие ключи, как 03
и 3
.