Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如何根据文件数量将文件夹内容复制到多个文件夹?_Linux_Bash - Fatal编程技术网

Linux 如何根据文件数量将文件夹内容复制到多个文件夹?

Linux 如何根据文件数量将文件夹内容复制到多个文件夹?,linux,bash,Linux,Bash,我想根据文件数(此处:50)将文件从一个文件夹(名为:1)复制到多个文件夹 下面给出的代码有效。我根据文件数将文件夹中的所有文件传输到子文件夹,然后将目录中的所有文件复制回初始文件夹。 但是,我需要更干净、更高效的东西。为下面的混乱道歉,我是个裸体 bf=1 #breakfolder cd 1 #the folder from where I wanna copy stuff, contains 179 files flies_exist=$(ls -1q * | wc -l) #assign

我想根据文件数(此处:50)将文件从一个文件夹(名为:1)复制到多个文件夹

下面给出的代码有效。我根据文件数将文件夹中的所有文件传输到子文件夹,然后将目录中的所有文件复制回初始文件夹。 但是,我需要更干净、更高效的东西。为下面的混乱道歉,我是个裸体

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是不好的。

假设您需要更紧凑/高效的工具,您可以利用现有工具(find、xargs)创建管道,无需使用bash对每个步骤进行编程

以下操作将文件移动到拆分文件夹中。它将找到文件,将它们分组,每个文件夹50个,使用awk生成输出文件夹,并移动文件。解决方案不如原始解决方案优雅:-(

作为旁注,当前脚本将文件从“1”文件夹移动到带编号的文件夹,然后将文件复制回原始文件夹。为什么不将文件复制到带编号的文件夹。如果需要,可以使用“cp-p”保留时间戳

支持使用新行(和空格)的文件名

对问题的澄清表明,解决方案应使用嵌入新行(和while空格)的文件名。这需要对使用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

对文件中的空间和新行进行了有限的测试。在我的机器上看起来不错。

假设您需要更紧凑/高效的工具,您可以利用现有工具(find、xargs)创建管道,无需使用bash对每个步骤进行编程

以下操作将文件移动到拆分文件夹中。它将查找文件,将其分组,每个文件夹50个,使用awk生成输出文件夹,然后移动文件。解决方案不如原始解决方案优雅:-(

作为旁注,当前脚本将文件从“1”文件夹移动到带编号的文件夹,然后将文件复制回原始文件夹。为什么不将文件复制到带编号的文件夹。如果需要,可以使用“cp-p”保留时间戳

支持使用新行(和空格)的文件名

对问题的澄清表明,解决方案应使用嵌入新行(和while空格)的文件名。这需要对使用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!@$%^&*(\u+-=?')


这将文件复制到多个固定大小的文件夹中。根据需要更改源、目标和文件夹大小。这也适用于具有特殊字符的文件名(例如,
'file 131@$%^&*()_+-=;?'


我发现发布的脚本有几个问题:

  • 每个文件夹最多复制50个文件的逻辑过于复杂,整个循环的代码复制容易出错

  • 它使用重用位置参数的
    $@
    数组用于内部存储。此变量不是用于此目的的,最好使用新的专用数组

  • 与其将文件移动到子目录,然后再将其复制回来,不如在第一步中只复制它们,而不移动它们

  • 不建议分析
    ls
    的输出

考虑这个更简单的替代逻辑:

  • 初始化空数组
    以进行复制
    ,以保留应复制的文件
  • 初始化文件夹计数器,用于计算目标文件夹
  • 在源文件上循环
    • 像以前一样应用筛选器(如果不是文件,则跳过)
    • 将文件添加到
      以复制
    • 如果要复制的
      包含目标文件数,则:
    • 创建目标文件夹
    • 中包含的文件复制到\u Copy
    • 的内容重置为\u copy
      为空
    • 增量
      文件夹\u计数器
  • 如果要复制的
    不为空
    
    • 创建目标文件夹
    • 中包含的文件复制到\u 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

顺便说一句,我的代码的最后一步给出了这个警告,如果有人能解释发生了什么以及解决方案,我会很高兴的

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'
当然可以。命令
find CompiledPdfOutput/temp/-exec cp{}1\
查找文件和目录,并尝试复制它们。当
cp
遇到目录且未指定
-r
参数时,它会发出您看到的警告。您可以为文件添加一个过滤器,使用
-type f
。如果没有过多的文件,则简单的shell glob将完成此任务:

cp -v CompiledPdfOutput/temp/*/* 1

我发现发布的脚本有几个问题:

  • 每个文件夹最多复制50个文件的逻辑过于复杂,整个循环的代码复制容易出错

  • 它使用重用位置参数的
    $@
    数组用于内部存储。此变量不是用于此目的的,最好使用新的专用数组

  • 而不是将文件移动到子目录,然后将其复制回来,