首页 > 解决方案 > 将包含多个文件的文件夹移动到另一个目录

问题描述

POWER SHELL ERROR 代码和目录的图片

我想创建一个批处理文件,将包含多个文件的所有文件夹移动到另一个目录。

我尝试了下面的代码

mkdir "OOOO3_MORE_THAN_ONE"
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) 
        #i f count=2 then move 
        if [ "$count" -le 1 ]; then 
            # move dir 
            mv -v "$dir" /completepath/"OOOO3_MORE_THAN_ONE" 
        fi
    fi
done

我只是得到一个新文件夹,里面没有任何文件夹。包含多个文件的文件夹没有移动到新目录

我也尝试了下面的代码,它有点不同,但仍然导致一个空文件夹

#! /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 > 1 )) && mv -v -- "$dir" "$destdir"
done

标签: sh

解决方案


好吧,你有两个问题(如最初发布的那样)。

(1)您在当前工作目录/completepath/OOOO3_MORE_THAN_ONE中创建后尝试移动到。除非您在创建目录时执行脚本,否则您的调用将失败。(这里的双引号是多余的)"OOOO3_MORE_THAN_ONE"/completepath./OOOO3_MORE_THAN_ONEmv -v "$dir" /completepath/"OOOO3_MORE_THAN_ONE"

(2)你有一个“鸡和蛋”的问题,因为你:

mkdir "OOOO3_MORE_THAN_ONE"

在您致电之前:

for dir in *; do

(在您调用and之前OOOO3_MORE_THAN_ONE包含在,但不排除在外)'*'findmv

OOOO3_MORE_THAN_ONE因此,当您的列表中出现其名称时,您将有效地尝试移动到其下方。

那么如何纠正这些问题呢?

重新排列你的代码。由于您的问题被标记[sh](POSIX shell),您没有可用于预存储countdir名称的数组的好处,但您始终可以使用创建的临时文件mktemp. 在开始更改目录结构之前,您需要通读每个标识的目录条目并将for dir in *所有信息写入临时文件。然后您可以简单地遍历临时文件中的条目,检查是否并移动到您的新条目,例如countdir$count -gt 1$dir

#!/bin/sh

## initialize newdir from 1st argument (or default: OOOO3_MORE_THAN_ONE)
newdir="${1:-OOOO3_MORE_THAN_ONE}"

## set your complete path from 2nd arg (or '.' by default)
cmpltpath="${2:-.}"

## now create a temporary file to hold count dirname pairs
tmpfile=$(mktemp)

for dir in *; do    ## write count and dirname pairs to temporary file
    [ -d "$dir" ] && echo "$(find "$dir" -type f | wc -l) $dir" >> "$tmpfile"
done

## now create the directory to move to using cmpltpath, exit on failure
mkdir -p "$cmpltpath/$newdir" || exit 1

## read count and dirname from tmpfile & move if count > 1
while read -r count dir || [ -n "$dir" ]; do
    ## if count=2 then move 
    if [ "$count" -gt 1 ]; then 
        ## move to dir 
        mv -v "$dir" "$cmpltpath/$newdir" 
    fi
done < "$tmpfile"

rm "$tmpfile"   ## tidy up and remove tmpfile (or set trap after mktemp)

注意:脚本将创建和移动文件的目录名称作为脚本的第一个参数(位置参数),并将完整路径(绝对或相对)放在新目录之前)

另请注意:如果您有 bash(或其他支持关联数组的高级 shell),您可以简单地将目录名称和计数保存在以目录名称为键的关联数组中,并完全避免使用临时文件)

原目录

使用目录树,其中每个子目录下d1, d2, d3都有1, 2 or 3文件,例如:

$ tree
.
├── d1
│   └── file1
├── d2
│   ├── file1
│   └── file2
├── d3
│   ├── file1
│   ├── file2
│   └── file3
└── mvscript.sh

示例使用/生成的目录结构

现在运行脚本会将所有具有大于 1 个文件的目录移动到您的新目录中:

$ sh mvscript.sh
'd2' -> './OOOO3_MORE_THAN_ONE/d2'
'd3' -> './OOOO3_MORE_THAN_ONE/d3'

$ tree
.
├── OOOO3_MORE_THAN_ONE
│   ├── d2
│   │   ├── file1
│   │   └── file2
│   └── d3
│       ├── file1
│       ├── file2
│       └── file3
├── d1
│   └── file1
└── mvscript.sh

你的第二种方法

您的第二种方法还不错,但除非您有一些特殊要求并且需要匹配点文件,否则您可能需要调整而不是按照本节中指定GLOBIGNORE的设置。另请注意,第一行的和之间没有空格。dotglobman bashPathname Expansion#!/bin/bash

您第二次尝试的基本调整可能是:

#!/bin/bash

destdir='subset'

mkdir -p -- "$destdir" || exit 1

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 -printf ".\n" | wc -l)
    (( numfiles > 1 )) && mv -v -- "$dir" "$destdir"
done

示例使用/输出

类似的测试将导致:

$ bash mvscript2.sh
'd2' -> 'subset/d2'
'd3' -> 'subset/d3'

$ tree
.
├── d1
│   └── file1
├── mvscript2.sh
└── subset
    ├── d2
    │   ├── file1
    │   └── file2
    └── d3
        ├── file1
        ├── file2
        └── file3

推荐阅读