在 bash 中处理数组值

在 bash 中处理数组值

我试图根据文件名创建一个数组,但遇到了空格问题。这似乎很常见。但是 - 据我所知 - 引号设置正确,我想这一定是数组的构建方式。

to_dump="$(find . -maxdepth 1 -print0 )"
to_dump_array=($to_dump)

read -p " ->  " final
case "$final" in
   a) for drop in "${to_dump_array[@]}" ;
      do cp "$drop" --recursive --force Destination_Folder && \
      echo "dropped \"$drop\" ;
      done ;;
   b) echo "Won't drop anything" ;;
esac

我想应该有一种更好的方法来从查找查询构建数组。另外,我还有哪里错了?

答案1

-print0不应在$(...)替换中使用,因为 bash 变量中的字符串以 null 结尾。

我问了一个问题,其答案与这个问题的要求类似:https://stackoverflow.com/a/30469553/1091693

将该答案调整为您的问题:

to_dump=()
while IFS= read -r -d ''; do
  to_dump+=( "$REPLY" )
done < <(find . -maxdepth 1 -print0)

这将创建一个名为 的数组to_dump,并使用该read命令从 中读取 NULL 分隔的元素find。这里使用而不是管道的原因< <(...)是为了避免隐式子shell,这会阻止数组被修改。

值得注意的是,您的原始find命令可能需要一个-mindepth 1, 或者它会选择.(当前目录),您最终将对其进行递归复制。


我注意到你使用-maxdepth 1作为 find 的参数,所以也许这会更有用:

shopt -s nullglob
to_dump=( * .[!.]* ..?* )

避免find,这仅使用 bash 内置函数,不会分叉,并且大部分都非常干净。

第一行shopt -s nullglob是一个 bash(-only) 命令,用于打开该nullglob选项。该选项的描述如下man 1 bash

如果设置,bash 允许不匹配任何文件的模式(请参阅上面的路径名扩展)扩展为空字符串,而不是它们本身。

简单来说,如果您输入*但与文件不匹配,它将删除*.默认行为是*无论如何都将其放在那里。

第二行向数组添加 3 个 glob:

  • *:所有不以以下开头的文件.
  • .[!.]*.:所有以一个和一个非字符开头的文件.。这是为了避免匹配...目录。
  • ..?*:所有以..和 至少一个字符开头的文件。添加的原因与之前的 glob 相同,涵盖了它遗漏的情况。

Bash 将 glob 扩展到数组的定义中,并且正确地扩展它们——不会在空格或类似的情况下进行分割。

关于使用 nullglob 的警告:如果您打开了 nullglob,curl google.com/search?q=test将会导致curl 抱怨您没有传递它的参数,并且ls /var/fasdfasafs*会给您当前目录的列表。这是默认情况下未打开的原因之一。

答案2

尝试像这样构建数组:

read -d $'\0' -r -a to_dump <<< $(find . -maxdepth 1 -print0)

答案3

 find . -maxdepth 1

...在我看来表明你想要:

a=()
for f in ./..?* ./.[!.]* ./*
do  [ -e "$f" ] && a+=$f
done

答案4

我不确定你的脚本正在做你认为它正在做的事情。我不认为这会将 find 的 null 终止输出转换为文件名的 bash 数组:

to_dump_array=($to_dump)

您是否检查过 for 循环的输出以了解您得到了什么?

for drop in "${to_dump_array[@]}"
do
    echo -e "$drop\n"
done

存在堆栈溢出,并提供了一些有关从 find -print0 填充数组的建议。

https://stackoverflow.com/questions/1116992/capturing-output-of-find-print0-into-a-bash-array

您还可能更好地使用数组索引来处理数组项,而不是尝试直接在 for 循环中分配给变量,它避免了依赖 shell 的正确分割:

for drop in $(seq 0 $((${#to_dump_array[@]} - 1)))
do
    cp "${to_dump_array[$drop]}"

这可能不是很流行,但如果您需要使用 bash 数组和多个转义来管理文件名中的空格(以及其他更不寻常的字符),那么您可能会超出 shell 的设计目的。

您可能会发现 python、perl、ruby 等更快、更可靠、更容易管理和调试代码库。

我有许多“危险信号”,我用它们来告诉我何时可能超出了 shell 脚本编写的明智范围。

  • 多级转义或空终止来处理所有文件名情况。
  • 多层 shell 函数相互调用。
  • 复杂的数据结构。即超越字符串、数字。
  • 我发现自己在做“性能优化”。
  • 表达式中的“线路噪声”。

是的,您当然可以执行上述所有操作,但是您应该这样做吗?说真的......Python、perl、ruby 等。在Python 中就这么简单,你不需要担心转义或带有空格或二进制字符的文件名。

import os

dirListing = os.listdir("somedirectory")

for eachEntry in dirlisting:
    doSomething

相关内容