[英]How to copy the contents of a folder to multiple folders based on number of files?
我想根据文件的数量(这里:50)将文件从一个文件夹(名为:1)复制到多个文件夹。
下面给出的代码有效。 我根据文件的数量将所有文件从文件夹转移到子文件夹,然后将目录中的所有文件复制回初始文件夹。 但是,我需要更清洁、更高效的东西。 为下面的混乱道歉,我是一个nube。
bf=1 #breakfolder
cd 1 #the folder from where I wanna copy stuff, contains 179 files
flies_exist=$(ls -1q * | wc -l) #assign the number of files in folder 1
#move 50 files from 1 to various subfolders
while [ $flies_exist -gt 50 ]
do
mkdir ../CompiledPdfOutput/temp/1-$bf
set --
for f in .* *; do
[ "$#" -lt 50 ] || break
[ -f "$f" ] || continue
[ -L "$f" ] && continue
set -- "$@" "$f"
done
mv -- "$@" ../CompiledPdfOutput/temp/1-$bf/
flies_exist=$(ls -1q * | wc -l)
bf=$(($bf + 1))
done
#mover the rest of the files into one final subdir
mkdir ../CompiledPdfOutput/temp/1-$bf
set --
for f in .* *; do
[ "$#" -lt 50 ] || break
[ -f "$f" ] || continue
[ -L "$f" ] && continue
set -- "$@" "$f"
done
mv -- "$@" ../CompiledPdfOutput/temp/1-$bf/
#get out of 1
cd ..
# copy back the contents from subdir to 1
find CompiledPdfOutput/temp/ -exec cp {} 1 \;
所需的目录结构是:
parent
________|________
| |
1 CompiledPdfOutput
| |
(179) temp
|
---------------
| | | |
1-1 1-2 1-3 1-4
(50) (50) (50) (29)
“()”中的数字表示文件的数量。
顺便说一句,我的代码的最后一步给出了这个警告,如果有人能解释正在发生的事情和解决方案,我会很高兴。
cp: -r not specified; omitting directory 'CompiledPdfOutput/temp/'
cp: -r not specified; omitting directory 'CompiledPdfOutput/temp/1-4'
cp: -r not specified; omitting directory 'CompiledPdfOutput/temp/1-3'
cp: -r not specified; omitting directory 'CompiledPdfOutput/temp/1-1'
cp: -r not specified; omitting directory 'CompiledPdfOutput/temp/1-2'
我也不想复制目录,只是提供 -r 的文件会很糟糕。
我发现发布的脚本存在一些问题:
每个文件夹最多复制 50 个文件的逻辑过于复杂,并且整个循环的代码重复很容易出错。
它使用重用$@
位置参数数组来进行内部存储。 此变量不是为此而设计的,最好使用新的专用数组。
与其将文件移动到子目录然后将它们复制回来,不如在第一步中复制它们更简单,而无需移动。
不推荐解析ls
的output。
考虑这个替代的,更简单的逻辑:
to_copy
,以保留应该复制的文件to_copy
to_copy
包含目标文件数,则:to_copy
中包含的文件to_copy
的内容重置为空folder_counter
to_copy
不为空
to_copy
中包含的文件像这样的东西:
#!/usr/bin/env bash
set -euo pipefail
distribute_to_folders() {
local src=$1
local target=$2
local max_files=$3
local to_copy=()
local folder_counter=1
for file in "$src"/* "$src/.*"; do
[ -f "$file" ] || continue
to_copy+=("$file")
if (( ${#to_copy[@]} == max_files )); then
mkdir -p "$target/$folder_counter"
cp -v "${to_copy[@]}" "$target/$folder_counter/"
to_copy=()
((++folder_counter))
fi
done
if (( ${#to_copy[@]} > 0 )); then
mkdir -p "$target/$folder_counter"
cp -v "${to_copy[@]}" "$target/$folder_counter/"
fi
}
distribute_to_folders "$@"
要将path/to/1
中的文件分发到path/to/compiled-output
下最多 50 个文件的目录中,可以使用以下命令调用此脚本:
./distribute.sh path/to/1 path/to/compiled-output 50
顺便说一句,我的代码的最后一步给出了这个警告,如果有人能解释正在发生的事情和解决方案,我会很高兴。
当然。 命令find CompiledPdfOutput/temp/ -exec cp {} 1 \;
查找文件和目录,并尝试复制它们。 当cp
遇到目录并且未指定-r
参数时,它会发出您看到的警告。 您可以使用-type f
为文件添加过滤器。 如果文件不多,那么一个简单的 shell glob 就可以完成这项工作:
cp -v CompiledPdfOutput/temp/*/* 1
假设您需要更紧凑/更高效的东西,您可以利用现有工具(find、xargs)来创建管道,从而无需使用 bash 对每个步骤进行编程。
以下将文件移动到拆分文件夹中。 它将找到文件,将它们分组,每个文件夹 50 个,使用 awk 生成 output 文件夹,然后移动文件。 解决方案不如原始解决方案优雅:-(
find 1 -type f |
xargs -L50 echo |
awk '{ print "CompliedOutput/temp/1-" NR, $0 }' |
xargs -L1 echo mv -t
作为旁注,当前脚本将文件从“1”文件夹移动到编号文件夹,然后将文件复制回原始文件夹。 为什么不直接将文件复制到编号的文件夹中。 如果需要,您可以使用“cp -p”来保留时间戳。
支持带有新行(和空格)的文件名
澄清问题表明解决方案应使用嵌入新行(和空格)的文件名。 这需要稍作更改以使用 NUL 字符作为分隔符。
# Count number of output folders
DIR_COUNT=$(find 1 -type f -print0 | xargs -0 -I{} echo X | wc -l)
# Remove previous tree, and create folder
OUT=CompiledOutput/temp
rm -rf $OUT
eval mkdir -p $OUT/1-{1..$DIR_COUNT}
# Process file, use NUL as separator
find 1 -type f -print0 |
awk -vRS="\0" -v"OUT=$OUT" 'NR%50 == 1 { printf "%s/1-%d%s",OUT,1+int(NR/50),RS } { printf "%s", ($0 RS) }' |
xargs -0 -L51 -t mv -t
对文件中的空格和新行进行了有限的测试。 在我的机器上看起来不错。
这会将文件复制到多个固定大小的文件夹。 根据您的要求更改源、目标和文件夹大小。 这也适用于带有特殊字符的文件名(例如'file 131;@#$%^&*()_+-=??'
)。
source=1
target=CompiledPDFOutput/temp
folderSize=50
find $source -type f -printf "\"%p\"\0" \
| xargs -0 -L$folderSize \
| awk '{system("mkdir -p '$target'/1-" NR); printf "'$target'/1-" NR " %s\n", $0}' \
| xargs -L1 cp -t
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.