【问题标题】:How to loop through the sorted list of file names in two directories如何遍历两个目录中的文件名排序列表
【发布时间】:2017-12-18 06:20:40
【问题描述】:

请注意,我已经阅读过类似 For loop for files in multiple folders - bash shell 的条目,但他们要求的内容完全不同。

我想按存在于两个目录中的任何一个目录中的排序顺序遍历文件名。文件中可能包含空格。

假设我有:

1/
  a
  a c b
  b
  c
2/
  a
  d

我想循环遍历:'a'、'a c b'、'b'、'c'、'd'。

我已尝试执行以下操作:

for fname in $((ls -1 -f -A "${dir1}"; ls -1 -f -A "${dir2}")|sort --unique); do
  echo "testing ${fname}"
done

结果是

testing .
testing ..
testing a
testing a
testing c
testing b
testing b
testing c
testing d

无论出于何种原因,我都会得到“。”和“..”条目,我试图用-A 排除这些条目,并且文件“a c b”被分解为三个字符串。

我试图通过将--zero 添加到sort 命令来解决它,但没有任何改变;通过引用整个 $(ls...|sort) 部分,并导致进入 for 循环的单个条目,该条目已接收整个字符串,其中包含多行,每行包含文件名。

【问题讨论】:

  • for fname in 1/* 2/*; do ...; done?
  • 请将您想要的输出添加到您的问题中。
  • 嗨,实际上所需的输出已经存在:“我想循环遍历:'a', 'a c b', 'b', 'c', 'd'。”跨度>

标签: bash for-loop whitespace


【解决方案1】:

永远不要有意识地解析ls 命令的输出(参见Why you shouldn't parse the output of ls(1)),它有很多潜在的陷阱。使用find 命令及其-print0 选项对文件进行空分隔,以便处理带有空格/换行符或任何元字符的文件名,然后使用具有相同空分隔字符的GNU sort,按字母顺序对它们进行排序& 删除重复文件。如果dir1dir2 是包含要查找的文件夹名称的shell 变量,您可以这样做

while IFS= read -r -d '' file; do
    printf '%s\n' "$file"
done< <(find "${dir1}" "${dir2}" -maxdepth 1 -type f -printf "%f\0" | sort -t / -u -z) 

【讨论】:

    【解决方案2】:

    一种更简单的方法可能是遍历所有内容并通过其他方式排除重复项。

    #!/bin/bash
    # Keep an associative array of which names you have already processed
    # Requires Bash 4
    declare -A done
    for file in 1/* 2/*; do
        base=${file#*/}  # trim directory prefix from value
        test "${done[$base]}" && continue
        : do things ...
        done["$base"]="$file"
    done
    

    【讨论】:

    • 我认为这会使文件名的排序变得非常困难。
    • 然后我必须捕获此输出并将其放入另一个循环中以实际处理它们?
    • 嗯,是的,如果您的要求是严格按字母顺序处理文件,那么这可能不是您想要的答案,或者至少不是最优雅的解决方案。
    【解决方案3】:

    答案:

    1. 使用以下命令将 for 分隔符从空格更改为 \n

      IFS=$'\n'
      
    2. 您使用-l 表示 ls,这意味着-a(并覆盖-A);请改用--color=never

    总结一下:

    IFS=$'\n'
    for fname in $((ls -1 --color=never -A "${dir1}"; ls -1 --color=never -A "${dir2}")|sort --unique); do
      echo "testing ${fname}"
    done
    

    【讨论】:

    • 在 bash 中,你需要使用 IFS=$'\n' 而不是 IFS=\n,我已修复
    猜你喜欢
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 2014-10-02
    • 2013-03-04
    相关资源
    最近更新 更多