本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/linux-copy-directory-ignore-files/ 近日在 Linux 环境中做版本迁移的时候遇到一个问题:需要将一个目录遍历拷贝到另一个目录中,但需要忽略其中的某些文件,由于目录中东西比较多,忽略的项也不好一一指定。普通的 cp 命令并没有排除某个文件或文件夹的参数,比较丑陋点可以 cp -r 拷贝完目录之后再去删除无用的,但如果做批量脚本操作就不爽了,经过实际试验之后暂时找到两个比较好的方法。 1、使用 rsync 进行拷贝: rsync 本来是文件同步备份的工具,相对于普通的 cp 命令,rsync 在控制方面就强多了,而且 rsync 对遍历目录也支持,有 --exclude 参数可以忽略指定的文件或文件夹。 rsync -vaP --exclude=”.*” --exclude=”Makefile” dir1 /home/dir2 如上面演示的就可以排除掉隐藏文件和 Makefile 文件,-a 参数已经包含遍历处理参数 -r。 2、使用 find 加 cpio 进行拷贝: 备注:此方法来自 Advanced Bash-Scripting Guide,需要了解的童鞋自己去参考了。 用过 find 的童鞋都知道,find 对文件的过滤那是非常强大的,配合 cpio 来进行目录的遍历拷贝就可以实现过滤指定的文件或文件夹,当然也可以做到只备份特定的文件或文件夹,你可以用 find 的各种过滤参数达到拷贝哪天的文件,拷贝近期更改的文件等特殊效果,而且 find 支持正则表达式,这种方式想比第一种使用 rsync 跳过文件的方式更加灵活,因此非常推荐使用此方式进行目录拷贝。 cd dir1 find . -regextype posix-egrep -mindepth 1 ! -regex ‘./(dev|tmp)($|/.*)’ ! -name Makefile -a ! -name .svn | cpio -admvp /home/dir2 小解释下: find 的 -regextype 参数指定正则表达式类型,posix-egrep 为 egrep 用的扩展正则表达式,-mindepth 使 find 的输出中不包括目录本身,-regex 参数指定过滤的文件的正则表达式,-regex 前面的感叹号表示跳过,’./(dev|tmp)($|/.*)’ 这个正则表达式即表示跳过目录中的第一层 dev 和 tmp 目录以及下面所有的文件和文件夹,最后两个 -name 指定要跳过文件名为 Makefile 和 .svn 的文件,这样在备份版本库的时候非常有用。 cpio 命令将 find 的输出文件列表依次拷贝到 /home/dir2 目标目录中,-a 表示不更新文件的访问时间,-d 指定自动创建目录,-m 指定保留文件的修改时间,-p 指定 cpio 工作在 Copy-pass 模式,这是专门用来拷贝目录树的一种模式。 PS:如果有更加简单的方法,欢迎提出指正哦~~~ ^_^
Tag: Copy
vector的push_back拷贝构造和空间占用分析
本文同步自:https://zohead.com/archives/vector-push-back-space-copy/ 这两天在实际程序中使用 STL 的 vector push_back 类对象时出现问题,偶尔发现 vector 在 push_back 时的调用类对象的拷贝构造函数和析构函数有点特别,简单做下分析。 程序代码: 功能很简单,main 中定义一个 sss 类对象和对应的 vector,然后在循环中改类成员的值,并依次 push_back 到 vector 中,类的构造函数、析构函数、拷贝构造函数中都加了对应的打印输出。循环运行了5次,往 vector 中增加了5个类成员。 实际运行输出如下: ---init sss 0x22ff20, value:11 ---copy 0x22ff20 to 0x5d2a58 size: 1, capacity: 1 ---copy 0x5d2a58 to 0x5d2ad8 ---copy 0x22ff20 to 0x5d2adc ---destory sss 0x5d2a58, value:12 size: 2, capacity: 2 ---copy 0x5d2ad8 to 0x5d2ae8 ---copy 0x5d2adc to 0x5d2aec ---copy 0x22ff20 to 0x5d2af0 ---destory sss 0x5d2ad8, value:12 ---destory sss 0x5d2adc, value:13 size: 3, capacity: 4 ---copy 0x22ff20 to 0x5d2af4 size: 4, capacity: 4 ---copy 0x5d2ae8 to 0x5d2b00 ---copy 0x5d2aec to 0x5d2b04 ---copy 0x5d2af0 to 0x5d2b08 ---copy 0x5d2af4 to 0x5d2b0c ---copy 0x22ff20 to 0x5d2b10 ---destory sss 0x5d2ae8, value:12 ---destory sss 0x5d2aec, value:13 ---destory sss 0x5d2af0, value:14 ---destory sss 0x5d2af4, value:15 size: 5, capacity: 8 ---destory sss 0x5d2b00, value:12 ---destory sss 0x5d2b04, value:13 ---destory sss 0x5d2b08, value:14 ---destory sss 0x5d2b0c, value:15 ---destory sss 0x5d2b10, value:16 ---destory sss 0x22ff20, value:16 结果分析: vector 每次调用 push_back 时都会拷贝一个新的参数指定的 sss 类对象,这会调用 sss 的拷贝构造函数,第一次的 copy 正常,而且 vector 的实际容量也由 0 变为 1。 第二次调用 push_back,通过输出会发现调用了两次拷贝构造函数,一次析构函数,原来 vector 此时判断容量不够,将容量扩大为原来的两倍,变为 2,并将原来的元素再次拷贝一份存放到新的内存空间,然后拷贝新加的类对象,最后再释放原来的元素。 第三次调用 push_back 时,vector 自动扩大为4,因此拷贝构造函数调用了3次,析构函数调用了2次,程序最终退出了时就析构了 5 次加本身的 sss 类对象一共 6 次。 参考: 由此看来,vector 的 push_back 在发现空间不足时自动将空间以 2 的指数增长:0 -> 1 -> 2 -> 4 -> 8 -> 16 -> 32 … 查找资料后得知,如此设计的主要目的是为了尽可能的减小时间复杂度;如果每次都按实际的大小来增加 vector 的空间,会造成时间复杂度很高,降低 push_back 的速度。 另外关于 push_back 为什么会执行拷贝构造函数,push_back 的原型为: void push_back(const _Ty& _Val) 参数是以引用方式传递,按说不会拷贝,但 push_back 实际实现中判断空间不足时是调用 insert 函数添加元素: void push_back(const _Ty& _Val) { // insert element at end if (size() < capacity()) #if _HAS_ITERATOR_DEBUGGING { // room at end, construct it there _Orphan_range(_Mylast, _Mylast); _Mylast = _Ufill(_Mylast, 1, _Val); } #else /* _HAS_ITERATOR_DEBUGGING */ _Mylast = _Ufill(_Mylast, 1, _Val); #endif /* _HAS_ITERATOR_DEBUGGING */ else insert(end(), _Val); } 更新: 2012-05-10: 近期在 Visual Studio 2010 中发现 vector 的实际空间增加顺序为:1 - 2 - 3 - 4 […]