如何从数组中删除所有以特定字符结尾的字符串

问题描述

我有一个数组,其中包含不同级别目录中的文件路径列表。我只想将该数组过滤为仅文件,这意味着以/结尾的文件应保留在数组中。在我的文件系统上,所有路径都不是真实路径。我可以使用OS工具检查目录/文件的类型。

我有一个包含以下字符串的数组:

file-a
dir/
dir/file-b
dir/dir-2/
dir/dir-2/file-c

并希望将其过滤为以下字符串(无目录):

file-a
dir/file-b
dir/dir-2/file-c

我尝试了以下方法,但是删除了所有包含/的路径,导致file-a是唯一的剩余路径。

FILES_ARRAY=( ${FILES_ARRAY[@]//*\/} )

我试图添加一个$(在正则表达式语法中很常见)来表示结尾,该结尾不会从数组中删除任何内容

FILES_ARRAY=( ${FILES_ARRAY[@]//*\$/} )

解决方法

两种不同的解决方案,具体取决于filter的含义:

1-从数组中删除目录条目:

declare -a FILES_ARRAY=([0]="file-a" [1]="dir/" [2]="dir/file-b" [3]="dir/dir-2/" [4]="dir/dir-2/file-c")
echo "++++++++++++++ array - before"
printf "%s\n" ${FILES_ARRAY[@]}

for i in ${!FILES_ARRAY[@]}
do
    [[ "${FILES_ARRAY[${i}]}" == */ ]] && unset FILES_ARRAY[${i}]       # remove director from array
done

echo "++++++++++++++ array - after"
printf "%s\n" ${FILES_ARRAY[@]}

这将生成:

++++++++++++++ array - before
file-a
dir/
dir/file-b
dir/dir-2/
dir/dir-2/file-c
++++++++++++++ array - after
file-a
dir/file-b
dir/dir-2/file-c

2-将目录条目保留在数组中,但不显示它们;我们可以通过更改for循环的主体来重新使用以上代码:

declare -a FILES_ARRAY=([0]="file-a" [1]="dir/" [2]="dir/file-b" [3]="dir/dir-2/" [4]="dir/dir-2/file-c")
echo "++++++++++++++ array"
printf "%s\n" ${FILES_ARRAY[@]}

echo "++++++++++++++ display"
for i in ${!FILES_ARRAY[@]}
do
    [[ "${FILES_ARRAY[${i}]}" != */ ]] && echo "${FILES_ARRAY[${i}]}"   # only display non-directory entries
done

这还会生成:

++++++++++++++ array
file-a
dir/
dir/file-b
dir/dir-2/
dir/dir-2/file-c
++++++++++++++ display
file-a
dir/file-b
dir/dir-2/file-c
,

您可以使用

FILES_ARRAY=(file-a dir/ dir/file-b dir/dir-2/ dir/dir-2/file-c)
NEW_FILES_ARRAY=()
for (( i=0; i<${#FILES_ARRAY[@]}; i++ )); do 
  if ! [[ "${FILES_ARRAY[$i]}" == */ ]]; then
    NEW_FILES_ARRAY+=("${FILES_ARRAY[$i]}");
  fi
done
FILES_ARRAY=("${NEW_FILES_ARRAY[@]}")

printf '%s\n' ${FILES_ARRAY[@]}

输出:

file-a
dir/file-b
dir/dir-2/file-c

查看online Bash demo

注释

  • for (( i=0; i<${#FILES_ARRAY[@]}; i++ )); do ... done遍历FILES_ARRAY的长度,为i分配了数组元素的索引
  • if ! [[ "${FILES_ARRAY[$i]}" == */ ]]检查当前元素是否不以/结尾(*匹配任意数量的字符,/匹配/ glob 模式始终需要整个字符串匹配,不需要$)和
  • NEW_FILES_ARRAY+=("${FILES_ARRAY[$i]}");将当前项目添加到NEW_FILES_ARRAY数组中。
  • FILES_ARRAY=("${NEW_FILES_ARRAY[@]}")重新分配了原始变量,使其包含过滤后的元素
,

awk命令可能会有所帮助,但路径中的空格会失败

new_arr=($(awk '{for (i=1; i<=NF; i++) if ($i !~ /\/$/) {print $i}}' <<< "${arr[@]}"))