Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.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 Bash脚本将目录结构从源目录复制到目标目录_Linux_Bash_Shell_Scripting - Fatal编程技术网

Linux Bash脚本将目录结构从源目录复制到目标目录

Linux Bash脚本将目录结构从源目录复制到目标目录,linux,bash,shell,scripting,Linux,Bash,Shell,Scripting,我对Bash Scriptping非常陌生,为了获得一些实践,我正在尝试编写一个脚本,该脚本包含一个源目录和一个目标目录。脚本将搜索源目录并将其子目录结构复制到目标目录中。任何文件都将被忽略,只是目录本身将被复制。源目录在任何深度都可以有任意数量的子目录。实现这一目标的最佳方式是什么?我开始尝试编写一个递归函数,如果找到一个目录,该函数将被递归调用到此目录。然而,由于我缺乏编写脚本的经验,我被难倒了 以下是我到目前为止的情况: #! /bin/bash if [ ! $# -eq 2 ]; t

我对Bash Scriptping非常陌生,为了获得一些实践,我正在尝试编写一个脚本,该脚本包含一个源目录和一个目标目录。脚本将搜索源目录并将其子目录结构复制到目标目录中。任何文件都将被忽略,只是目录本身将被复制。源目录在任何深度都可以有任意数量的子目录。实现这一目标的最佳方式是什么?我开始尝试编写一个递归函数,如果找到一个目录,该函数将被递归调用到此目录。然而,由于我缺乏编写脚本的经验,我被难倒了

以下是我到目前为止的情况:

#! /bin/bash

if [ ! $# -eq 2 ]; then 
    echo "ERROR: Script needs 2 arguments: $0 source/directory/ target/directory/"
    exit
fi

SOURCE_DIR=$1
TARGET_DIR=$2

function searchForDirectory {
    for FILE in ls $SOURCE_DIR/*; do #should be 'ls *current_directory*'
        if [ -d $FILE ]; then
            searchForDirectory #call function recursively onto $FILE
            #Do stuff here to create copy of this directory in target dir
        fi
    done
}

if [ ! -d $SOURCE_DIR ]; then 
    echo "ERROR: Source directory does not exist"
    exit
else
    searchForDirectory
fi
我知道这只是一个框架函数,需要做更多的工作,但我只是想在我进一步研究之前找到一些指导,看看这是否是正确的方法,如果是的话,我的下一步是什么?如何将目录传递到函数中

编辑:这是我的解决方案,感谢下面伊万的帮助 ! /bin/bash

if [ ! $# -eq 2 ]; then 
    echo -e "\nERROR: Script needs 2 arguments:\n$0 source/directory/ target/directory/\n"
    exit
fi

function recursiveDuplication {
    for file in `ls $1`; do
        if [ -d $1/$file ] && [ ! -d $2/$file ]; then
            mkdir $2/$file
            recursiveDuplication $1/$file $2/$file
        elif [[ $1/$file == *.png ]]; then
            convert $1/$file $2/$file
        fi
    done
}

if [ ! -d $1 ]; then 
    echo -e "\nERROR: $1 does not exist\n"
    exit
elif [ -d $2 ] && [ ! -w $2 ]; then
    echo -e "\nERROR: You do not have permission to write to $2\n"
    exit
elif [ ! -d $2 ]; then
    echo -e "\nSUCCESS: $2 has been created"
    mkdir $2
fi

recursiveDuplication $1 $2
此解决方案存在两个问题:

( cd source/ ; find . -depth -type d -printf "%p\0" | xargs -0 -I xxx mkdir -p ../destination/xxx )
正如Rany Alberg Wein在下面解释的那样,使用“ls”并不是一个好的解决方案——我已经了解了为什么在目录/*.png名称中有空格

我还试图将任何*.png文件从源文件复制到目标文件,并将其转换为目标文件中的*.jpg图像。我该怎么做?我试图使用ImageMagick的convert image.png image.jpg命令,但不知道在image.png被称为$file时如何操作

你可以简化很多

$ find a -type d | xargs -I d mkdir -p copy/d
将树结构从目录a复制到“复制”下的新目录

你可以简化很多

$ find a -type d | xargs -I d mkdir -p copy/d
将树结构从目录a复制到“复制”下的新目录


这个解决方案已经用包含特殊字符的目录名、目录树中的一个循环和一个断开的符号链接进行了测试

下面是一个stansard解决方案:

( cd source/ ; find . -depth -type d -printf "%p\0" | xargs -0 -I xxx mkdir -p ../destination/xxx )
还有第二个使用gnu cpio的解决方案:

测试:

$ mkdir -p source/a/ba/c/d/e
$ mkdir -p source/a/bb/c/d/e
$ mkdir -p source/a/b/ca/d/e
$ ln -s source/broken/link source/a/ba/c/d/e/broken
$ (cd source/a/ba && ln -s ../../a  tree-loop)
$ mkdir -p source/z/"$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47\72\73\74\75\76\77\100\133\134\135\1336\137\140\173\174\175\176\177dir")" 
$ touch source/a/b/"$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47\72\73\74\75\76\77\100\133\134\135\1336\137\140\173\174\175\176\177file")"
$ ls 
source
$ find source -depth
source/z/??????????????????????????????? !"#$%&':;<=>?@[\][6_`{|}~?dir
source/z
source/a/ba/tree-loop
source/a/ba/c/d/e/broken
source/a/ba/c/d/e
source/a/ba/c/d
source/a/ba/c
source/a/ba
source/a/b/ca/d/e
source/a/b/ca/d
source/a/b/ca
source/a/b/??????????????????????????????? !"#$%&':;<=>?@[\][6_`{|}~?file
source/a/b
source/a/bb/c/d/e
source/a/bb/c/d
source/a/bb/c
source/a/bb
source/a
source

$ ( cd source/ ; find . -depth -type d -printf "%p\0" | xargs -0 -I xxx mkdir -p ../destination/xxx )
$ find destination/ -depth 
destination/z/??????????????????????????????? !"#$%&':;<=>?@[\][6_`{|}~?dir
destination/z
destination/a/ba/c/d/e
destination/a/ba/c/d
destination/a/ba/c
destination/a/ba
destination/a/b/ca/d/e
destination/a/b/ca/d
destination/a/b/ca
destination/a/b
destination/a/bb/c/d/e
destination/a/bb/c/d
destination/a/bb/c
destination/a/bb
destination/a
destination/

这个解决方案已经用包含特殊字符的目录名、目录树中的一个循环和一个断开的符号链接进行了测试

下面是一个stansard解决方案:

( cd source/ ; find . -depth -type d -printf "%p\0" | xargs -0 -I xxx mkdir -p ../destination/xxx )
还有第二个使用gnu cpio的解决方案:

测试:

$ mkdir -p source/a/ba/c/d/e
$ mkdir -p source/a/bb/c/d/e
$ mkdir -p source/a/b/ca/d/e
$ ln -s source/broken/link source/a/ba/c/d/e/broken
$ (cd source/a/ba && ln -s ../../a  tree-loop)
$ mkdir -p source/z/"$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47\72\73\74\75\76\77\100\133\134\135\1336\137\140\173\174\175\176\177dir")" 
$ touch source/a/b/"$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47\72\73\74\75\76\77\100\133\134\135\1336\137\140\173\174\175\176\177file")"
$ ls 
source
$ find source -depth
source/z/??????????????????????????????? !"#$%&':;<=>?@[\][6_`{|}~?dir
source/z
source/a/ba/tree-loop
source/a/ba/c/d/e/broken
source/a/ba/c/d/e
source/a/ba/c/d
source/a/ba/c
source/a/ba
source/a/b/ca/d/e
source/a/b/ca/d
source/a/b/ca
source/a/b/??????????????????????????????? !"#$%&':;<=>?@[\][6_`{|}~?file
source/a/b
source/a/bb/c/d/e
source/a/bb/c/d
source/a/bb/c
source/a/bb
source/a
source

$ ( cd source/ ; find . -depth -type d -printf "%p\0" | xargs -0 -I xxx mkdir -p ../destination/xxx )
$ find destination/ -depth 
destination/z/??????????????????????????????? !"#$%&':;<=>?@[\][6_`{|}~?dir
destination/z
destination/a/ba/c/d/e
destination/a/ba/c/d
destination/a/ba/c
destination/a/ba
destination/a/b/ca/d/e
destination/a/b/ca/d
destination/a/b/ca
destination/a/b
destination/a/bb/c/d/e
destination/a/bb/c/d
destination/a/bb/c
destination/a/bb
destination/a
destination/


Meh,这是相同的,因为在问题中,不要使用ls输出进行任何操作。ls是一个交互式查看目录元数据的工具。使用代码解析ls输出的任何尝试都将被中断。Globs更加简单和正确:用于*.txt中的文件。Read idem名称、权限和符号链接中的特殊字符是什么?@RanyAlbegWein请参阅我的编辑,其中解释了使用ls时遇到的问题,正如您所解释的。如果不使用ls,我如何使用相同的for循环?@KOB请查看我之前评论中的链接。你会学到解决问题的正确方法。嗯,这是一样的,就像问题一样,不要用ls输出做任何事情。ls是一个交互式查看目录元数据的工具。使用代码解析ls输出的任何尝试都将被中断。Globs更加简单和正确:用于*.txt中的文件。Read idem名称、权限和符号链接中的特殊字符是什么?@RanyAlbegWein请参阅我的编辑,其中解释了使用ls时遇到的问题,正如您所解释的。如果不使用ls,我如何使用相同的for循环?@KOB请查看我之前评论中的链接。您将学习解决问题的正确方法。如果您感兴趣,可以通过find和cpio来完成。查找源类型d | cpio-pd目标。源中的整个树将复制到目标。如果该命令由root用户执行,则可以保留权限和所有权。如果由非root用户执行,则只能保留权限。@KOB已使用gnu CPOI在测试过的安全解决方案中添加了一个新答案。如果您感兴趣,可以通过find和cpio来完成。查找源类型d | cpio-pd目标。源中的整个树将复制到目标。如果该命令由root用户执行,则可以保留权限和所有权。如果由非root用户执行,则只能保留权限。@KOB已使用gnu CPIOAL使用测试过的安全解决方案添加了一个新答案,尽管OP没有指定是否保留权限和所有权,您应该提到的是,使用此方法不会保留任何内容。此外,包含特殊字符´*``\n的目录名会破坏此否?那么符号链接呢?此外,mkdir将尝试创建由于-p而已经创建的目录,生成错误,对吗?@karakfa此解决方案无法复制目录树,请参阅我答案中的测试。生成此错误:xargs:不匹配的双引号;默认情况下,除非使用-0选项,否则引号对于xargs是特殊的,尽管OP没有使用sp
指定是否保留权限和所有权,您应该提到,使用此方法不会保留任何权限和所有权。此外,包含特殊字符´*```\n的目录名将破坏此否?那么符号链接呢?此外,mkdir将尝试创建由于-p而已经创建的目录,生成错误,对吗?@karakfa此解决方案无法复制目录树,请参阅我答案中的测试。生成此错误:xargs:不匹配的双引号;默认情况下,除非使用-0选项,否则引号对于xargs是专用的