Я написал пример сценария для разделения строки, но он не работает должным образом
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
вывод
One
XX
X
17.0.0
17 0 0
но я ожидал, что результат будет:
One
XX
X
17.0.0
17
0
0
bash
shell-script
lfs
user112232
источник
источник
Ответы:
Исправьте (см. Также ответ С. Чазеласа для фона), с разумным выводом:
Вывод:
Ноты:
Лучше поставить условный 2 - й цикл в в 1 - м цикле.
bash
pattern substitution ("${i//.}"
) проверяет.
наличие элемента. (case
Утверждение может быть проще, хотя и менее похоже на код OP .)read
ING$array
, вводя<<< "${ADDR[3]}"
меньше общего , чем<<< "$i"
. Это позволяет избежать необходимости знать, какой элемент имеет.
s.Код предполагает, что печать « Элемент: 17.0.0 » является непреднамеренной. Если Такое поведение является предназначено заменить основной цикл с:
источник
case $i in (*.*) ...
был бы более канонический способ проверки, который$i
содержит.
(и также переносимsh
). Если вы любите кшизмы, см. Также:[[ $i = *.* ]]
case
в примечаниях в конце, но мы согласны. (Так как OP использует оба<<<
и массивы , это не большойsh
вопрос.)В старых версиях
bash
вам приходилось заключать в кавычки переменные после<<<
. Это было исправлено в 4.4. В более старых версиях переменная разделялась на IFS, и результирующие слова объединялись в пространстве перед сохранением во временном файле, который составляет это<<<
перенаправление.В 4.2 и ранее, при перенаправлении встроенных функций, таких как
read
илиcommand
, такое разбиение даже получило бы IFS для этой встроенной функции (4.3 исправило это):Это исправлено в 4.3:
Но там
$a
все еще есть разделение слов:В 4.4:
Для переносимости в более старые версии, укажите вашу переменную (или используйте,
zsh
откуда она<<<
взялась, и у которой нет этой проблемы)Обратите внимание, что такой подход для разделения строки работает только для строк, которые не содержат символов новой строки. Также не отметить , что
a..b.c.
должно быть разделено на"a"
,""
,"b"
,"c"
(не пустой последний элемент).Чтобы разделить произвольные строки, вы можете использовать вместо этого оператор split + glob (который сделает его стандартным и позволит избежать хранения содержимого переменной во временном файле, как это
<<<
делается):или:
''
Является сохранение завершающую пустой элемент , если таковые имеются. Это также разделило бы пустое$var
на один пустой элемент.Или используйте оболочку с правильным оператором разбиения:
zsh
:rc
:fish
источник
С awk это обойдется вам в одну строку:
-F'[-.]'
- разделитель полей, основанный на нескольких символах, в нашем случае-
и.
Выход:
источник
IFS=-. read -r a array <<< "$IN"
Вот мой путь:
результат, как и ожидалось:
источник
$IN
вызывает оператор split + glob. Здесь вам не нужна глобальная часть (примерьте,IN=*-*-/*-17.0.0
например), поэтому вы захотите сделать этоset -o noglob
перед ее вызовом. Смотрите мой ответ для деталей.IFS
и установки его глобально. Вы действительно хотите изменить только значение,IFS
когда$IN
раскрывается, и вы также не хотите, чтобы расширение расширения выполнялось для расширения. Кроме того,OIFS=$IFS
не делает различий между случаями, когдаIFS
была задана пустая строка, и когда онаIFS
была полностью не установлена.