复制其中包含两个以上文件的目录

时间:2019-05-03 13:22:58

标签: bash

我有很多目录;其中很多文件只有1个或2个。

我想将其中包含两个以上文件的目录复制到另一个目录中,如何检查并移动目录?

到目前为止,我对脚本还是很满意,但是我不确定。

#!/bin/bash

mkdir "subset"
for dir in *; do
        #if the file is a directory
        if [ -d "$dir" ]; then
            #count number of files
            count=$(find "$dir" -type f | wc -l)
            #if count>=2 then move
            if [ "$count" -ge 2 ]; then
                #move dir
                #   ...
            fi
        fi
done

命令mv $dir ..将目录上移一个,但是是否可以在subset中上移和下移而不使用完整路径mv $dir complete_path/subset

3 个答案:

答案 0 :(得分:3)

如果要处理任意目录名称和内容,则有很多陷阱和陷阱。这段Shellcheck干净的代码试图避免所有这些:

#! /bin/bash -p

shopt -s nullglob   # glob patterns that match nothing expand to nothing
shopt -s dotglob    # glob patterns expand names that start with '.'

destdir='subset'

[[ -d $destdir ]] || mkdir -- "$destdir"

for dir in * ; do
    [[ -L $dir ]] && continue               # Skip symbolic links
    [[ -d $dir ]] || continue               # Skip non-directories
    [[ $dir -ef $destdir ]] && continue     # Skip the destination dir.

    numfiles=$(find "./$dir//." -type f -print | grep -c //)
    (( numfiles > 2 )) && mv -v -- "$dir" "$destdir"
done
  • shopt -s nullglob表示,如果代码在空目录中运行,代码将起作用。 (否则,它将尝试处理名为“ *”的虚假目录条目。)
  • shopt -s dotglob使代码能够处理名称以“。”开头的目录。 (例如.mydir)。
  • 您可以通过将循环防护更改为for dir in */ ...来避免稍后在代码中进行目录检查,但这会使符号链接的检查稍微复杂化。
  • 代码假定您不希望将符号链接移动到包含两个以上文件([[ -L $dir ]] && continue)的目录中。如果该假设不正确,请删除该行。
  • 计算目录下的文件数量非常麻烦,因为文件名称中可以包含换行符,这意味着find ... | wc -l可能无法正常工作。请参见How can I get a count of files in a directory using the command line?
    find"./$dir//.")所困扰的第一个参数旨在避免多个陷阱。引号可以防止目录名称中的特殊字符引起问题。如果目录名称以./开头,则-前缀避免将参数视为选项。后缀//.意味着find找到的每个文件在一行上都只有一个'//',因此grep -c //将准确地计算文件数。
  • --mkdir命令的mv参数是为了确保如果$dir$destdir以{{1}开头的话,它们可以正常工作。 }(这会使它们被视为选项)。参见Bash Pitfalls #2 (cp $file $target)

答案 1 :(得分:0)

这是到目前为止我提出的最好的解决方案。

我想知道是否有更优雅的解决方案:

#!/bin/bash

mkdir "OOOO3_LESS_THAN_TWO"

for dir in *; do
        #if the file is a directory
        if [ -d "$dir" ]; then
            #count number of files
            count=$(find "$dir" -type f | wc -l)
            #if count<=2 then move
            if [ "$count" -le 2 ]; then
                #move dir
                mv -v "$dir" /completepath/"OOOO3_LESS_THAN_TWO"
            fi
        fi
done

答案 2 :(得分:0)

您的一般方法很好。不幸的是,没有一种明显优越的方法可以计算目录中有多少文件。

您可以通过遍历-d来摆脱*/的检查。尾随/意味着只有目录会匹配。

您可以结合作业和测试。您可能会喜欢它,也可能会觉得很奇怪。

您还可以使用((...))进行算术运算。我个人觉得它更具可读性。

for dir in */; do
    if count=$(find "$dir" -type f | wc -l) && ((count >= 2)); then
        ...
    fi
done

或者您可以完全忽略count变量。

for dir in */; do
    if (($(find "$dir" -type f | wc -l) >= 2)); then
        ...
    fi
done

可以通过一次find调用来完成所有这些操作,但是现在我们肯定在 arcane 地区。

find . -type d \
    -exec bash -c '(($(compgen -G "$1/*" | wc -l) > 2))' bash {} \; \
    -exec mv {} subset/ \;

  

命令mv $dir ..将目录上移一个,但是是否可以在subset中上移和下移而不使用完整路径mv $dir complete_path/subset

您尚未更改目录,因此请使用所需的任何相对路径。如果我理解这个问题,它可能很简单,例如mv <dir> subset/