bash 列出文件夹中的所有子目录,将它们写入数组以在菜单中使用
bash list all subdirectories in a folder, write them to array to use in a menu
我正在写一个bash脚本,我在某个目录中有多个子文件夹,我想列出子文件夹的名称并将结果读入一个数组,省略某个单个文件夹从结果中调用 'cmmdm'。将名称读入数组后,我想生成一个菜单,其中每个子菜单名称作为一个选项,然后我将根据用户做出的选择对给定的子文件夹执行一个功能。
编辑:
抱歉应该添加我的初始代码:
#!/bin/bash
# - create array
declare -a CDARRAY
# - set 0 to exit in prep for menu
CDARRAY[0]=exit
# - create a counter to use in while loop
count=1
# - while loop to itterate through folder and add each folder except cmmdm into array
ls -d /home/nginx/domains/* | {
while read CMMDOMAIN ; do
if [ $CMMDOMAIN != "/home/nginx/domains/cmmdm" ]
then
$CDARRAY[$count]=$CMMDOMAIN
echo $CDARRAY[$count]
count=$[count + 1]
fi
done
}
这会遍历文件夹并忽略 'cmmdm' 但是我将变量 CMMDOMAIN 添加到数组的代码是错误的。我以前从未在 bash 中编写过脚本,所以我想可能是我的语法错误或缺少一些大括号或其他内容
find 可以吗?
DIRS=$(find ${PWD} -maxdepth 1 -type d)
echo ${DIRS}
或者可能是 for 循环(这需要您自己制作数组)?
for DIR in $(find ${PWD} -maxdepth 1); do if $(test -d ${DIR}); then echo $(basename ${DIR}); fi; done
有人告诉我使用如下所示的 "Internal Field Separator" (IFS) 是一个更安全的解决方案(防止奇怪,例如 fild/directory 名称中的白色字符)
while IFS= read -r DIR; do echo "${DIR}"; done < <(find . -maxdepth 1 -type d -printf "%P\n")
你的代码有很多问题,这里讨论的太多了(无意冒犯)。
这是一个完整的示例,它会根据需要显示菜单,并进行一些常见的检查:
#!/bin/bash
shopt -s extglob nullglob
basedir=/home/nginx/domains
# You may omit the following subdirectories
# the syntax is that of extended globs, e.g.,
# omitdir="cmmdm|not_this_+([[:digit:]])|keep_away*"
# If you don't want to omit any subdirectories, leave empty: omitdir=
omitdir=cmmdm
# Create array
if [[ -z $omitdir ]]; then
cdarray=( "$basedir"/*/ )
else
cdarray=( "$basedir"/!($omitdir)/ )
fi
# remove leading basedir:
cdarray=( "${cdarray[@]#"$basedir/"}" )
# remove trailing backslash and insert Exit choice
cdarray=( Exit "${cdarray[@]%/}" )
# At this point you have a nice array cdarray, indexed from 0 (for Exit)
# that contains Exit and all the subdirectories of $basedir
# (except the omitted ones)
# You should check that you have at least one directory in there:
if ((${#cdarray[@]}<=1)); then
printf 'No subdirectories found. Exiting.\n'
exit 0
fi
# Display the menu:
printf 'Please choose from the following. Enter 0 to exit.\n'
for i in "${!cdarray[@]}"; do
printf ' %d %s\n' "$i" "${cdarray[i]}"
done
printf '\n'
# Now wait for user input
while true; do
read -e -r -p 'Your choice: ' choice
# Check that user's choice is a valid number
if [[ $choice = +([[:digit:]]) ]]; then
# Force the number to be interpreted in radix 10
((choice=10#$choice))
# Check that choice is a valid choice
((choice<${#cdarray[@]})) && break
fi
printf 'Invalid choice, please start again.\n'
done
# At this point, you're sure the variable choice contains
# a valid choice.
if ((choice==0)); then
printf 'Good bye.\n'
exit 0
fi
# Now you can work with subdirectory:
printf "You chose subdirectory \`%s'. It's a good choice.\n" "${cdarray[choice]}"
评论应该非常清楚地解释发生了什么。用于构建数组的技术是 extended globs,这也是您提出问题的目的。例如:
shopt -s extglob nullglob
cdarray=( /home/nginx/domains/!(cmmdm)/ )
将使用 /home/nginx/domains/
的所有不匹配 cmmdm
的子目录填充 cdarray
(完全匹配)。拥有所有不以 a
或 b
结尾的子目录:
shopt -s extglob nullglob
cdarray=( /home/nginx/domains/!(*[ab])/ )
我正在写一个bash脚本,我在某个目录中有多个子文件夹,我想列出子文件夹的名称并将结果读入一个数组,省略某个单个文件夹从结果中调用 'cmmdm'。将名称读入数组后,我想生成一个菜单,其中每个子菜单名称作为一个选项,然后我将根据用户做出的选择对给定的子文件夹执行一个功能。
编辑: 抱歉应该添加我的初始代码:
#!/bin/bash
# - create array
declare -a CDARRAY
# - set 0 to exit in prep for menu
CDARRAY[0]=exit
# - create a counter to use in while loop
count=1
# - while loop to itterate through folder and add each folder except cmmdm into array
ls -d /home/nginx/domains/* | {
while read CMMDOMAIN ; do
if [ $CMMDOMAIN != "/home/nginx/domains/cmmdm" ]
then
$CDARRAY[$count]=$CMMDOMAIN
echo $CDARRAY[$count]
count=$[count + 1]
fi
done
}
这会遍历文件夹并忽略 'cmmdm' 但是我将变量 CMMDOMAIN 添加到数组的代码是错误的。我以前从未在 bash 中编写过脚本,所以我想可能是我的语法错误或缺少一些大括号或其他内容
find 可以吗?
DIRS=$(find ${PWD} -maxdepth 1 -type d)
echo ${DIRS}
或者可能是 for 循环(这需要您自己制作数组)?
for DIR in $(find ${PWD} -maxdepth 1); do if $(test -d ${DIR}); then echo $(basename ${DIR}); fi; done
有人告诉我使用如下所示的 "Internal Field Separator" (IFS) 是一个更安全的解决方案(防止奇怪,例如 fild/directory 名称中的白色字符)
while IFS= read -r DIR; do echo "${DIR}"; done < <(find . -maxdepth 1 -type d -printf "%P\n")
你的代码有很多问题,这里讨论的太多了(无意冒犯)。
这是一个完整的示例,它会根据需要显示菜单,并进行一些常见的检查:
#!/bin/bash
shopt -s extglob nullglob
basedir=/home/nginx/domains
# You may omit the following subdirectories
# the syntax is that of extended globs, e.g.,
# omitdir="cmmdm|not_this_+([[:digit:]])|keep_away*"
# If you don't want to omit any subdirectories, leave empty: omitdir=
omitdir=cmmdm
# Create array
if [[ -z $omitdir ]]; then
cdarray=( "$basedir"/*/ )
else
cdarray=( "$basedir"/!($omitdir)/ )
fi
# remove leading basedir:
cdarray=( "${cdarray[@]#"$basedir/"}" )
# remove trailing backslash and insert Exit choice
cdarray=( Exit "${cdarray[@]%/}" )
# At this point you have a nice array cdarray, indexed from 0 (for Exit)
# that contains Exit and all the subdirectories of $basedir
# (except the omitted ones)
# You should check that you have at least one directory in there:
if ((${#cdarray[@]}<=1)); then
printf 'No subdirectories found. Exiting.\n'
exit 0
fi
# Display the menu:
printf 'Please choose from the following. Enter 0 to exit.\n'
for i in "${!cdarray[@]}"; do
printf ' %d %s\n' "$i" "${cdarray[i]}"
done
printf '\n'
# Now wait for user input
while true; do
read -e -r -p 'Your choice: ' choice
# Check that user's choice is a valid number
if [[ $choice = +([[:digit:]]) ]]; then
# Force the number to be interpreted in radix 10
((choice=10#$choice))
# Check that choice is a valid choice
((choice<${#cdarray[@]})) && break
fi
printf 'Invalid choice, please start again.\n'
done
# At this point, you're sure the variable choice contains
# a valid choice.
if ((choice==0)); then
printf 'Good bye.\n'
exit 0
fi
# Now you can work with subdirectory:
printf "You chose subdirectory \`%s'. It's a good choice.\n" "${cdarray[choice]}"
评论应该非常清楚地解释发生了什么。用于构建数组的技术是 extended globs,这也是您提出问题的目的。例如:
shopt -s extglob nullglob
cdarray=( /home/nginx/domains/!(cmmdm)/ )
将使用 /home/nginx/domains/
的所有不匹配 cmmdm
的子目录填充 cdarray
(完全匹配)。拥有所有不以 a
或 b
结尾的子目录:
shopt -s extglob nullglob
cdarray=( /home/nginx/domains/!(*[ab])/ )