我正在使用bash脚本,该脚本应备份用户可以指定的文件夹。该脚本只是为了娱乐,并成为bash。我不会将其用于实际备份。
想法是用户可以输入他们想要更新的特定文件夹。每次输入后,他们将按ENTER
,然后在控制台中键入另一个目录。完成后,将按CTRL-D
。然后将输入保存到数组USER_DIR
中。然后将检查此数组以查看目录是否存在。如果它们确实存在,则条目将保持不变。如果它们不存在,则该条目将被覆盖为默认值/home/$USER
。
我在AskUbuntu上发现了一个有趣的主意(我正在使用Ubuntu):
while read line
do
my_array=("${my_array[@]}" $line)
done
echo ${my_array[@]}
我已经使用了它并尝试输入多个目录,但是只有在输入正好是一个目录的情况下,它才起作用。每次我使用多个目录作为输入时,它默认为/home/$USER
。我在脚本中的不同位置放置了echo ${my_array[@]}
,看起来好像问题出在分隔符上,因为输入似乎是由空格连接在一起的。
我试图寻找一种在保存输入后循环遍历数组并更改定界符的方法。我在StackOverflow上发现了一个有趣的主意:
SAVEIFS=$IFS # Save current IFS
IFS=$'\n' # Change IFS to new line
names=($names) # split to array $names
IFS=$SAVEIFS # Restore IFS
我尝试过,但是它也只接受单数输入。目前,我的脚本如下所示:
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
while read line
do
USER_DIR=("${USER_DIR[@]}" "$line")
done
SAVEIFS=$IFS # Save current IFS
IFS=$'\n' # Change IFS to new line
USER_DIR=($USER_DIR) # split to array $names
IFS=$SAVEIFS # Restore IFS
# check if user input in array is valid (directory exists)
for ((i=0; i<${#USER_DIR[@]}; i++))
do
if [[ -d "${USER_DIR[$i]}" ]]; then
# directory exists
USER_DIR=("${USER_DIR[@]}")
echo "${USER_DIR[@]}" # for debugging
else
# directory does not exist
USER_DIR=("/home/$USER")
echo "${USER_DIR[@]}" # for debugging
fi
done
# show content of array
echo "Backups of the following directories will be done:"
for i in "${USER_DIR[@]}"; do echo "$i"; done
任何帮助将不胜感激。感谢您的时间。
您不需要此代码段。
SAVEIFS=$IFS # Save current IFS
IFS=$'\n' # Change IFS to new line
USER_DIR=($USER_DIR) # split to array $names
IFS=$SAVEIFS # Restore IFS
默认情况下,读取命令使用\n
作为输入定界符。
Demo:
$./test.ksh
Please enter absolute path of directory for backup. Default is /home/renegade
You can choose multiple directories. Press CTRL-D to start backup.
abc
123
def
Backups of the following directories will be done:
abc
123
def
$cat test.ksh
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
while read line
do
USER_DIR=( "${USER_DIR[@]}" "$line" )
done
#SAVEIFS=$IFS # Save current IFS
#IFS=$'\n' # Change IFS to new line
#USER_DIR=($USER_DIR) # split to array $names
#IFS=$SAVEIFS # Restore IFS
# show content of array
echo "Backups of the following directories will be done:"
for i in "${USER_DIR[@]}"; do echo "$i"; done
$
这里有几个严重的问题,我也有一些更小的建议。第一个(可能)是次要的:您的脚本不是以shebang行开头来告诉系统它所使用的脚本语言。您使用的是bash功能(而不仅仅是基本的POSIX shell),因此您需要以shebang开头表示要运行bash,而不是某些通用shell。因此,第一行应为#!/bin/bash
或#!/usr/bin/env bash
。
接下来,让我们看一下while read
循环:
while read line
do
USER_DIR=("${USER_DIR[@]}" "$line")
done
此正常工作按原样。它使用用户的输入填充数组,每个条目一个元素。听起来好像您使用echo ${USER_DIR[@]}
检查了结果数组,并被误认为是有问题。但是循环工作正常,这是echo ${USER_DIR[@]}
引起误解。正如我在评论中所说,请改用declare -p USER_DIR
,bash将打印一条语句(如果您要运行它),它将重新创建数组的当前内容。事实证明,这是一种显示数组内容的好方法,通常毫不含糊。
我确实有一些小建议:请使用小写或大小写混合的变量名(例如user_dir
,userDir
或类似名称),而不要使用全大写字母的名称。一堆具有特殊含义的全大写字母名称,如果您使用全大写字母命名,很容易意外地使用其中的一个大写字母而引起混乱。另外,在用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)
仅获得第一个元素,尝试在换行符上进行拆分(因为这是IFS
设置的内容),但没有任何作用,因此没有任何反应。然后将USER_DIR
设置为由仅第一个元素。
本质上,它将删除数组中除第一个元素以外的所有元素。只需删除整个部分。
好,下一个:
for ((i=0; i<${#USER_DIR[@]}; i++))
这将在bash中用于具有默认索引(这是您所拥有的)的数组,但是我个人的喜好是改用它:
for i in "${!USER_DIR[@]}"
看到里面有!
吗?这样就可以得到数组中索引值的列表。在bash中工作,在zsh中工作(使用不同的编号约定),我不必试图记住哪个使用了哪个约定。它甚至可以与关联数组一起使用!但这又不是什么大问题,只是我的喜好。
现在,在循环内:
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")
这是第二个严重的问题。它用指向您的主目录的单个条目替换整个数组。您想要替换当前项的[[only并保留其余的数组,因此请使用USER_DIR[$i]="/home/$USER"
。请注意,数组引用周围没有${ }
-那些是当您从数组中获取的值时使用的,而不是当您<< setting >>一个的值时使用的。好吧,还有一个建议:与其将所有值读入数组然后再遍历以修复不存在的值,不如在读取目录路径时不进行存在性测试,然后直接添加首先要对数组进行正确处理?您甚至可以在用户输入名称时向用户提供反馈,例如:
#!/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