【问题标题】:How to remove all strings from array that end with a specific character如何从数组中删除以特定字符结尾的所有字符串
【发布时间】:2021-01-06 18:18:29
【问题描述】:

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

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

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[@]//*\$/} )

【问题讨论】:

  • ${FILES_ARRAY[@]//*\/} 不是正则表达式,此语法特定于使用 glob 进行 Bash 字符串操作。

标签: arrays bash glob end-of-line


【解决方案1】:

你可以使用

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&lt;${#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[@]}") 重新分配原始变量,以便它保存过滤后的元素

【讨论】:

  • 这个例子并不完全有效,因为我们在迭代数组的同时改变了它。这样,最后一个条目不会被处理,dir/dir-2/file-c 会丢失。
  • @SebastianBarth 好的,我调整了答案。
【解决方案2】:

两种不同的解决方案取决于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 directory 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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-22
      相关资源
      最近更新 更多