как сдвинуть значение массива в bash

8

мы хотим построить 6 папок точки монтирования в качестве примера

/data/sdb
/data/sdc
/data/sdd
/data/sde
/data/sdf
/data/sdg

поэтому мы написали этот простой скрипт bash, используя массив

folder_mount_point_list="sdb sdc sdd sde sdf sdg"

folderArray=( $folder_mount_point_list )

counter=0
for i in disk1 disk2 disk3 disk4 disk4 disk5 disk6
do
folder_name=${folderArray[counter]}
mkdir /data/$folder_name
let counter=$counter+1
done

Теперь мы хотим изменить код без счетчика и пусть = $ counter = counter + 1

Можно ли сдвинуть каждый цикл массива, чтобы получить следующее значение массива?

как-то так

${folderArray[++]}
Яэль
источник
1
для чего for i in disk1 disk2 disk3 disk4 disk4 disk5 disk6он не используется внутри тела цикла?
РоманПерехрест
1
... а какой смысл использовать счетчик? Почему бы тебе просто не убежать for i in "your_list_goes_here"; do mkdir /data/"$i"; done?
don_crissti

Ответы:

10

Общее замечание. Нет смысла определять массив следующим образом:

folder_mount_point_list="sdb sdc sdd sde sdf sdg"
folderArray=( $folder_mount_point_list )

Вы бы сделали это вместо этого:

folderArray=(sdb sdc sdd sde sdf sdg)

Теперь к вашему вопросу:

set -- sdb sdc sdd sde sdf sdg
for folder_name; do
    mkdir "/data/$folder_name"
done

или

set -- sdb sdc sdd sde sdf sdg
while [ $# -gt 0 ]; do
    mkdir "/data/$1"
    shift
done
Хауке Лагинг
источник
мы можем сделать набор для переменной как set - $ list_of_folders (while list_of_folders = "sdb sdc sdd sde"
yael
@yael Да, вы можете использовать, set -- $list_of_foldersно еще раз: строковые переменные не подходят:set -- "${folders[@]}"
Hauke ​​Laging
1
почему ты вообще пользуешься set -- ....? этот хак нужен только в оболочках, которые не поддерживают массивы - в оболочке, которая поддерживает массивы, он не нужен. for folder_name in "${folderArray[@]}"; do ... ; doneэто все, что нужно.
Cas
только один вопрос, есть ли выбор сделать что-то вроде - $ {folderArray [++]}
yael
@ CAC это то, что я имею в своем ответе. Я тоже не понимаю такой setподход.
PesaThe
14

Чтобы ответить на вопрос в заголовке, вы можете «сдвинуть» массив с помощью обозначения подстроки / подмассива. ( shiftСам работает только с позиционными параметрами.)

$ a=(a b c d e)
$ a=("${a[@]:1}")
$ echo "${a[@]}"
b c d e

Аналогично, чтобы «вытолкнуть» последний элемент из массива: a=("${a[@]:0:${#a[@]} - 1}" )илиunset "a[${#a[@]}-1]"

Итак, если вы хотите, вы можете сделать это:

a=(foo bar doo)
b=(123 456 789)
while [ "${#a[@]}" -gt 0 ] ; do
    echo "$a $b"
    a=("${a[@]:1}")
    b=("${b[@]:1}")
done

Но он разрушает массивы, так что обычное индексирование может быть лучше. Или может вместо этого использовать ассоциативный массив:

declare -A arr=([foo]=123 [bar]=456 [doo]=789)
ilkkachu
источник
4

Вы можете просто перебрать все значения без необходимости сдвига:

folderArray=(sdb sdc sdd sde sdf sdg)

for folder in "${folderArray[@]}"; do
    mkdir "/data/$folder"
done
PesaThe
источник
3

Вам не нужен цикл для этого:

folderArray=(sdb sdc sdd sde sdf sdg)
IFS=,
eval mkdir /data/{"${folderArray[*]}"}

Хитрость заключается в том, что если массив заключен в двойные кавычки с помощью subscript *( "${array[*]}"), он расширяется до одного слова со значением каждого элемента массива, разделенного первым символом IFSпеременной. После этого мы используем механизм расширения фигурных скобок для присоединения /data/к каждому элементу массива и evalиспользования всего этого.

jimmij
источник
Почему так сложно? cd /data ; mkdir "${folderArray[@]}"Я делал то же самое раньше, но в таком случае я бы этого не сделал. Но +1 за продвинутый подход.
Хауке Лагинг
@HaukeLaging Да, это было бы проще в случае mkdirкоманды. И даже массив не нужен, cd /data; mkdir abc defкак сделал бы нормальный человек. Но не может быть так просто для других задач, поэтому полезно знать, как быстро прикрепить строку к каждому элементу массива без цикла.
Джимми
только один вопрос, есть ли выбор сделать что-то вроде - $ {folderArray [++]}
yael
1
@yael Вы можете сделать что-то вроде, echo "${folderArray[((counter++))]}"если вам действительно нравится этот подход. Материал внутри (())оценивается как математика (обратите внимание на отсутствие $перед counter).
Джимми
1
и когда вы начинаете писать подобный код, вы понимаете, что было бы неплохо потратить немного времени на изучение Perl или Python. то есть то, что вы можете что-то сделать с помощью bash, не означает, что вы должны это делать .
Cas