Здесь есть пара серьезных проблем, и у меня есть еще несколько небольших рекомендаций. Первый (вероятно) второстепенный: ваш сценарий не начинается со строки shebang, чтобы сообщить системе, на каком языке сценариев он написан. Вы используете bash функции (а не только базовую c оболочку POSIX), поэтому вам нужно начните с shebang, который говорит, что нужно запускать bash, а не с какой-нибудь обобщенной c оболочкой Таким образом, первая строка должна быть либо #!/bin/bash
или #!/usr/bin/env bash
.
Далее, давайте посмотрим на while read
l oop:
while read line
do
USER_DIR=("${USER_DIR[@]}" "$line")
done
Это работает правильно как есть. Он заполняет массив вводом пользователя, по одному элементу на запись. Похоже, вы использовали echo ${USER_DIR[@]}
, чтобы проверить полученный массив, и запутались, думая, что что-то не так; но l oop работает нормально, это echo ${USER_DIR[@]}
, что вводит в заблуждение. Как я уже сказал в комментарии, вместо этого используйте declare -p USER_DIR
, а bash напечатает инструкцию, которая (если бы вы ее запустили) воссоздала текущее содержимое массива. Это оказывается хорошим, как правило, однозначным способом отображения содержимого массива.
У меня есть несколько небольших рекомендаций: используйте имена переменных в нижнем или смешанном регистре (например, user_dir
, userDir
, или что-то в этом роде) вместо имен всех заглавных букв. Существует множество названий всех заглавных букв со специальным значением, и если вы используете названные заглавные буквы, легко использовать одно из них и вызвать хаос. Кроме того, я бы инициализировал массив пустым до l oop с user_dir=()
, просто чтобы убедиться, что он начинается пустым. И, как сказал Jetchisel в комментарии, user_dir+=("$line")
будет более простым способом добавления новых элементов в массив. Только не оставляйте скобки, иначе он будет добавлен к первому элементу вместо добавления нового элемента.
Хорошо, следующий раздел:
SAVEIFS=$IFS # Save current IFS
IFS=$'\n' # Change IFS to new line
USER_DIR=($USER_DIR) # split to array $names
IFS=$SAVEIFS # Restore IFS
Это выглядит как попытка решить проблему, которая не существует, которая в конечном итоге создает новую проблему в процессе. Как я уже сказал, USER_DIR
уже существует как (правильно заполненный) массив, поэтому $USER_DIR
(без [@]
или чего-либо еще) просто получает свой первый элемент. Это означает, что USER_DIR=($USER_DIR)
получает только первый элемент, пытается разбить его на новые строки (потому что для этого установлено значение * 1029), но их нет, поэтому ничего не происходит. Затем он устанавливает USER_DIR
в массив, состоящий из только этого первого элемента .
По сути, он удаляет все, кроме первого элемента из массива. Просто избавьтесь от всего этого раздела.
Хорошо, следующий:
for ((i=0; i<${#USER_DIR[@]}; i++))
Это будет работать в bash для массива с индексацией по умолчанию (что у вас есть), но мое личное предпочтение - использовать это вместо:
for i in "${!USER_DIR[@]}"
Видите, что там !
? Это позволяет получить список значений индекса в массиве. Работает в bash, работает в zsh (который использует другое соглашение о нумерации), и мне не нужно пытаться вспомнить, какой из них использует какое соглашение. Это даже работает с ассоциативными массивами! Но опять же, это не имеет большого значения, просто мои предпочтения.
Теперь внутри l oop:
if [[ -d "${USER_DIR[$i]}" ]]; then
# directory exists
USER_DIR=("${USER_DIR[@]}")
Это расширяет содержимое массива (правильно указано и все таким образом, это не будет испорчено), и назначает это прямо обратно в массив. Это абсолютно ничего не делает! Имейте в виду, что здесь нет ничего правильного, но есть гораздо более простые способы ничего не делать. Я бы полностью удалил его и просто использовал if [[ ! -d "${USER_DIR[$i]}" ]]; then
, а затем часть «что делать, если его не существует». Кстати, о:
else
# directory does not exist
USER_DIR=("/home/$USER")
Это вторая серьезная проблема. Он заменяет весь массив одной записью, указывающей на ваш домашний каталог. Вы хотите заменить только текущей записью и оставить остальную часть массива в покое, поэтому используйте USER_DIR[$i]="/home/$USER"
. Обратите внимание, что вокруг ссылок на массивы нет ${ }
- это для случаев, когда вы получаете значение из массива, а не когда вы устанавливаете единицу.
Хорошо, еще одна рекомендация: вместо того, чтобы читать все значения в массив и затем возвращаться к ним, чтобы исправить те, которые не существуют, почему бы просто не выполнить тест на существование, когда вы читаете пути к каталогам, а затем просто добавить правильная вещь для массива в первую очередь? Вы даже можете оставлять отзывы пользователей, когда они вводят имена, например:
#!/bin/bash
echo "Please enter absolute path of directory for backup. Default is ""/home/$USER"
echo "You can choose multiple directories. Press CTRL-D to start backup."
# save user input into array
user_dir=()
while read line
do
if [[ -d "$line" ]]; then
user_dir+=("$line")
else
echo "$line isn't an existing directory; we'll back up /home/$USER instead"
user_dir+=("/home/$USER")
fi
done
# show content of array
echo "Backups of the following directories will be done:"
for i in "${user_dir[@]}"; do echo "$i"; done