假设我有以下目录树结构:
./Original
├── Dir1
│ ├── Objects
│ └── Textures
├── Dir2
│ ├── SubDir1
│ │ └── SubSubDir1
│ │ ├── Objects
│ │ └── Textures
│ └── SubDir2
│ ├── Objects
│ └── Textures
└── Dir3
├── Objects
├── SubDir1
│ ├── Objects
│ └── Textures
└── Textures
而且我也有一个类似的结构(它实际上是原始目录的副本,没有对象和纹理目录:
./Copy
├── Dir1
├── Dir2
│ ├── SubDir1
│ │ └── SubSubDir1
│ └── SubDir2
└── Dir3
└── SubDir1
如何将所有对象和纹理目录及其文件从原始目录移动到复制目录中的相应位置?完成后应如下所示:
./Original
├── Dir1
├── Dir2
│ ├── SubDir1
│ │ └── SubSubDir1
│ └── SubDir2
└── Dir3
└── SubDir1
./Copy
├── Dir1
│ ├── Objects
│ └── Textures
├── Dir2
│ ├── SubDir1
│ │ └── SubSubDir1
│ │ ├── Objects
│ │ └── Textures
│ └── SubDir2
│ ├── Objects
│ └── Textures
└── Dir3
├── Objects
├── SubDir1
│ ├── Objects
│ └── Textures
└── Textures
注意事项:
- 原始目录中并非所有目录都有对象和纹理目录
- 对象和纹理目录被移动而不是复制
- 此外,原始目录和复制目录位于同一目录中,这是应该调用命令/函数的地方
请使用此命令来构建起始结构:
mkdir -p Original/Dir1/Objects Original/Dir1/Textures Original/Dir2/SubDir1/SubSubDir1/Objects Original/Dir2/SubDir1/SubSubDir1/Textures Original/Dir2/SubDir2/Objects Original/Dir2/SubDir2/Textures Original/Dir3/Objects Original/Dir3/Textures Original/Dir3/SubDir1/Objects Original/Dir3/SubDir1/Textures
mkdir -p Copy/Dir1 Copy/Dir2/SubDir1/SubSubDir1 Copy/Dir2/SubDir2 Copy/Dir3/SubDir1
答案1
这是一个模拟。运行后,如果确定一切正确,请删除echo
并再次运行:
shopt -s globstar
for d in **/{Objects,Textures}; do
echo mv "$d" "Copy/${d##Original/}"
done
解释:
- 打开 Bash 选项“globstar”会使 glob
**/
匹配零个或多个子目录。 - Bash 扩展
**/{Objects,Textures}
为**/Objects **/Textures
。 ${d##Original/}
Original/
意思是“从 的开头删除字符串$d
。
答案2
如果你想使用另一个位置来更新目录树,最好的工具是rsync
,次好的可能是tar
。编写 shell 脚本往往是小菜一碟:
rsync -aP --ignore-existing Original/ Copy
选项:
-a
告诉rsync
保留所有权、模式等。-P
打印进度信息--ignore-existing
意味着已经存在的文件Copy
将不会被触及。- 尾随的后面
/
指示Original
将rsync
的内容复制Original
到Copy
,而不是复制Original
自身。
Original
完成后删除,或使用--remove-source-files
文件选项rsync
在复制完成时删除文件。
答案3
这是你可以设法搬家的一种方法没有子目录的目录。
首先开启递归遍历:
shopt -s globstar
现在,你可以使用 进行递归遍历**
。你可以使用 将其关闭shopt -u globstar
,但下次打开 shell 时它仍然会关闭。
Copy
现在在和的父目录中Original
:
for d in Original/**/; do $(ls -lAq "$d" | grep -q '^d') || echo mv -vn -- "$d" Copy"${d/Original/}"; done
测试后删除echo
以实际移动目录(当然还有它们的内容 -mv
没有-r
标志)
让我们让它更易读一些
shopt -s globstar
for d in Original/**/; do
$(ls -lAq "$d" | grep -q '^d') ||
echo mv -vn -- "$d" Copy"${d/Original/}"
done
等等,我刚才是不是解析输出ls
?嗯,是的,我这样做了。但我认为这没问题(!)因为我认为在这种情况下我可以依赖输出的一致性。无论文件名包含什么字符,该ls -l
文件所在目录的输出都将以定义其类型和权限的字符串开头。在ls -l
所有目录列表中,都以 开头d
,例如
drwxrwxr-x 26 zanna zanna 4096 Oct 5 19:57 playground
即使换行符也不会搞乱这一点,因为?
如果我们添加,它们会显示为(即使在管道之后)-q
。
$(ls -lAq "$d" | grep -q '^d')
检查目录是否有一些子目录。grep
我们收集退出状态,而不是收集 的输出。如果命令成功,我们什么也不做,但如果失败,我们收集mv
目录(使用||
或 运算符,这意味着,如果前面的命令||
失败,则执行后面的命令)。
我们使用字符串操作来删除Original
,以便将目录复制到正确的位置Copy
。
结果如下:
$ tree
.
├── Copy
│ ├── Dir1
│ │ ├── Objects
│ │ └── Textures
│ ├── Dir2
│ │ ├── SubDir1
│ │ │ └── SubSubDir1
│ │ │ ├── Objects
│ │ │ └── Textures
│ │ └── SubDir2
│ │ ├── Objects
│ │ └── Textures
│ └── Dir3
│ ├── Objects
│ ├── SubDir1
│ │ ├── Objects
│ │ └── Textures
│ └── Textures
└── Original
├── Dir1
├── Dir2
│ ├── SubDir1
│ │ └── SubSubDir1
│ └── SubDir2
└── Dir3
└── SubDir1
答案4
以下是此方法可能对您起作用的示例。请注意,此脚本将与原始目录和复制目录在同一级别运行,并且可能需要根据您的实际需求进行调整。祝您好运。
#!/bin/bash
src="original"
dst="./copy"
function findLocation {
for i in `find $src/ -type d -name "$1"`; do
IFS='/' read -ra directories <<< "$i"
dirNum=${#directories[@]}
let "arrayNum=$dirNum-2"
arrs=()
for ((k=1 ; k<=$arrayNum; k++)); do
arrs+=("${directories[$k]}")
done
echo "===============================++++++++++++++++"
function join {
local IFS="$1"
shift
echo "$*"
}
constructDst=`join / ${arrs[@]}`
destination="$dst/$constructDst/"
if [ ! -d $destination ] ; then
mkdir -p $destination
echo "creating directory: $destination"
fi
if [ -d $i ]; then
echo "Moving $i to $destination"
mv $i -t $destination
fi
done
}
findLocation Textures
findLocation Objects