sh - 将包含多个文件的文件夹移动到另一个目录
问题描述
我想创建一个批处理文件,将包含多个文件的所有文件夹移动到另一个目录。
我尝试了下面的代码
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
解决方案
好吧,你有两个问题(如最初发布的那样)。
(1)您在当前工作目录/completepath/OOOO3_MORE_THAN_ONE
中创建后尝试移动到。除非您在创建目录时执行脚本,否则您的调用将失败。(这里的双引号是多余的)"OOOO3_MORE_THAN_ONE"
/completepath
./OOOO3_MORE_THAN_ONE
mv -v "$dir" /completepath/"OOOO3_MORE_THAN_ONE"
(2)你有一个“鸡和蛋”的问题,因为你:
mkdir "OOOO3_MORE_THAN_ONE"
在您致电之前:
for dir in *; do
(在您调用and之前OOOO3_MORE_THAN_ONE
包含在,但不排除在外)'*'
find
mv
OOOO3_MORE_THAN_ONE
因此,当您的列表中出现其名称时,您将有效地尝试移动到其下方。
那么如何纠正这些问题呢?
重新排列你的代码。由于您的问题被标记[sh]
(POSIX shell),您没有可用于预存储count
和dir
名称的数组的好处,但您始终可以使用创建的临时文件mktemp
. 在开始更改目录结构之前,您需要通读每个标识的目录条目并将for dir in *
所有信息写入临时文件。然后您可以简单地遍历临时文件中的条目,检查是否并移动到您的新条目,例如count
dir
$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
的设置。另请注意,第一行的和之间没有空格。dotglob
man bash
Pathname 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
推荐阅读
- powershell - Powershell、RunAs 与凭据
- excel - 添加第三个条件来自动过滤 VBA
- r - 使用 gsub 提取文本
- openstack - 如何将 Openstack 与 glusterfs cinder volume 集成
- python - UnboundLocalError - 赋值前引用
- r - 在 R 中使用不涉及方程的 ~ (在 S4 类函数内)?
- react-native - 在本机反应中解析照片:// URI
- python - 查找连接列的实用程序
- azure-service-fabric - Azure Service Fabric 中独立服务和方便调试的解决方案结构
- jquery - 在第一次单击时附加并在第二次按钮单击时分离