AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1153994
Accepted
WinEunuuchs2Unix
WinEunuuchs2Unix
Asked: 2019-06-26 16:44:37 +0800 CST2019-06-26 16:44:37 +0800 CST 2019-06-26 16:44:37 +0800 CST

将文件组 (Filename*) 复制到备份 (Filename*.bak)

  • 772

背景

在 Linux 中,您可以:

  • 列出一组文件ls Filename*
  • 删除一组文件rm Filename*
  • 移动一组文件mv Filename* /New/Directory
  • 但是您不能使用以下命令复制一组文件:cp Filename* *.bak

更改 Linuxcp命令以复制文件组

我有一组文件要复制,而无需逐个输入名称并使用以下cp命令:

$ ls gmail-meta3*
gmail-meta3                          gmail-meta3-REC-1558392194-26467821
gmail-meta3-LAB-1558392194-26467821  gmail-meta3-YAD-1558392194-26467821

如何使用旧的 DOS 命令之类的东西copy gmail-meta3* *.bak?

我不想四次输入类似的命令:

cp gmail-meta3-LAB-1558392194-26467821 gmail-meta3-LAB-1558392194-26467821.bak

我正在寻找一个脚本/函数/应用程序,它接受新旧文件名组的参数,而不是带有硬编码文件名的东西。例如,用户可以键入:

copy gmail-meta3* *.bak

或者他们可能会输入:

copy gmail-meta3* save-*
command-line cp ms-dos
  • 8 8 个回答
  • 8060 Views

8 个回答

  • Voted
  1. pa4080
    2019-06-27T04:48:29+08:002019-06-27T04:48:29+08:00

    sed以下是适用于此任务的一种非典型用法示例:

    sed -i.bak '' file-prefix*
    

    这样,实际上sed不会更改文件,因为我们没有提供任何命令'',但是由于该选项-i[suffix],它会为每个文件创建一个备份副本。我在搜索时发现了这种方法 是否有任何方法可以创建文件的备份副本,而无需输入两次文件名?

    • 16
  2. cbojar
    2019-06-26T19:21:11+08:002019-06-26T19:21:11+08:00

    您可以使用find:

    find . -max-depth 1 -name 'gmail-meta3*' -exec cp "{}" "{}.bak" \;
    

    这将在当前目录中找到.名称与 glob 模式匹配的所有文件(注意模式周围的单引号以防止 shell 通配符)。对于找到的每个文件,它将cp从 name 执行到 name.bak。这 \; 最后确保它将单独执行每个文件,而不是一次传递所有文件。最大深度为 1 只搜索当前目录而不是向下递归。

    • 15
  3. xiota
    2019-06-26T17:34:10+08:002019-06-26T17:34:10+08:00

    您可以将for循环与bash. 通常,我只会将其键入为单行,因为这不是我经常执行的任务:

    for f in test* ; do cp -a "$f" "prefix-${f}.ext" ; done
    

    但是,如果您需要它作为脚本:

    cps() {
       [ $# -lt 2 ] && echo "Usage: cps REGEXP FILES..." && return 1
    
       PATTERN="$1" ; shift
    
       for file in "$@" ; do
          file_dirname=`dirname "$file"`
          file_name=`basename "$file"`
          file_newname=`echo "$file_name" | sed "$PATTERN"`
    
          if [[ -f "$file" ]] && [[ ! -e "${file_dirname}/${file_newname}" ]] ; then
             cp -a "$file" "${file_dirname}/${file_newname}"
          else
             echo "Error: $file -> ${file_dirname}/${file_newname}"
          fi
       done
    }
    

    用法类似于 rename。去测试:

    pushd /tmp
    mkdir tmp2
    touch tmp2/test{001..100}     # create test files
    ls tmp2
    cps 's@^@prefix-@ ; s@[email protected]@' tmp2/test*    # create backups
    cps 's@[email protected]@' tmp2/test*    # more backups ... will display errors
    ls tmp2
    \rm -r tmp2                   # cleanup
    popd
    
    • 11
  4. steeldriver
    2019-06-26T17:07:25+08:002019-06-26T17:07:25+08:00

    最接近 DOS 范式的可能是mcp(来自mmv软件包):

    mcp 'gmail-meta3*' 'gmail-meta3#1.bak'
    

    如果zsh可用,它的贡献zmv模块可能更接近一点:

    autoload -U zmv
    
    zmv -C '(gmail-meta3*)' '$1.bak'
    

    ls无论如何,我都会避免-您自己的答案的变体对空格(包括换行符)是安全的

    printf '%s\0' gmail-meta3* | while IFS= read -r -d '' f; do cp -a -- "$f" "$f.bak"; done
    

    也许

    printf '%s\0' gmail-meta3* | xargs -0 -I{} cp -a -- {} {}.bak
    
    • 6
  5. Robert Riedl
    2019-06-27T06:03:37+08:002019-06-27T06:03:37+08:00

    rsync 唯一解决方案

    如果您只想备份文件,可以将它们复制到新目录

    rsync /path/to/dir/Filename* /path/to/backupdirectory

    这会将Filename文件从复制/path/to/dir/到/path/to/backupdirectory。


    rsync + 文件重命名

    如果你想让你的备份文件有一个后缀,那么事情就会变得很糟糕rsync......

    rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak

    这将用现有文件 ( ) 覆盖现有文件……-I但前提是它们 ( -u) 较新(它们不是)并创建带有后缀的备份。

    您也可以在同一目录中执行此操作。但最好排除现有备份。

    rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak --exclude '*.bak'

    • 5
  6. Best Answer
    WinEunuuchs2Unix
    2019-06-26T16:44:37+08:002019-06-26T16:44:37+08:00

    我把这个单行代码写进了我的~/.bashrc. find我想可以发布更好的答案。甚至更好的答案可以用 C 语言编写。希望这个问答能得到更好的答案:

    cps () {
        # cps "Copy Splat", copy group of files to backup, ie "cps Filename .bak"
        # Copies Filename1 to Filename1.bak, Filename2 to Filename2.bak, etc.
        # If Filename1.bak exists, don't copy it to Filename1.bak.bak
        for f in "$1"*; do [[ ! "$f" == *"$2" ]] && cp -a "$f" "$f$2"; done
    
        # OLD version comments suggested to remove 
        # ls "$1"* | while read varname; do cp -a "$varname" "$varname$2"; done
    }
    
    • for f in "$1"*; do:$1是gmail-meta3参数,f是匹配的文件列表。结合 gmail-meta3、gmail-meta3-LAB-9999 等的这种方式,执行以下操作
    • [[ ! "$f" == *"$2" ]] &&:$f和f上面一样。$2是.bak传递的参数。结合这意味着如果文件名没有以.bak(因为我们不想复制.bak和创建.bak.bak)结尾,那么请执行以下操作
    • cp -a "$f" "$f$2";将 gmail-meta3 复制到 gmail-meta3.bak 等。
    • done: 循环并获取gmail-meta3* 列表中的下一个文件名。

    cps gmail-meta3 .bak样本输出

    以这个问题为例,它的实际表现如下:

    ───────────────────────────────────────────────────────────────────────────────────────────
    rick@alien:~/gmail$ ll gmail-meta3*
    -rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3
    -rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3.bak
    -rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821
    -rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821.bak
    -rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821
    -rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821.bak
    -rw-rw-r-- 1 rick rick   728954 Jun 27 17:04 gmail-meta3-YAD-1558392194-26467821
    -rw-rw-r-- 1 rick rick   728954 Jun 27 05:46 gmail-meta3-YAD-1558392194-26467821.bak
    ───────────────────────────────────────────────────────────────────────────────────────────
    rick@alien:~/gmail$ cps gmail-meta3 .bak
    ───────────────────────────────────────────────────────────────────────────────────────────
    rick@alien:~/gmail$ ll gmail-meta3*
    -rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3
    -rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3.bak
    -rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821
    -rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821.bak
    -rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821
    -rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821.bak
    -rw-rw-r-- 1 rick rick   728954 Jun 27 17:04 gmail-meta3-YAD-1558392194-26467821
    -rw-rw-r-- 1 rick rick   728954 Jun 27 17:04 gmail-meta3-YAD-1558392194-26467821.bak
    ───────────────────────────────────────────────────────────────────────────────────────────
    rick@alien:~/gmail$ 
    

    注意:这将-a标志与cp命令一起使用以保留时间戳并让您更好地掌握文件备份。

    请注意文件副本的日期和时间与原件完全相同。如果-a省略该参数,它们将被赋予当前日期和时间,并且看起来不像真正的备份,只是文件大小相同。

    • 4
  7. pLumo
    2019-06-26T22:35:52+08:002019-06-26T22:35:52+08:00

    这个应该按要求做:

    cps(){ p="${@: -1}"; for f in "${@:1:$#-1}"; do cp -ai "$f" "${p//\?/$f}"; done  }
    

    用法:

    cps FILES... pattern
    Example 1: cps gmail-meta3* ?.bak
    Example 2: cps * save-?
    Example 3: cps * bla-?-blubb
    

    我选择了?因为#必须在它是模式的第一个字符时被引用,否则它被识别为注释的开始。

    测试:

    $ touch 'test};{bla#?"blubb'
    $ cps test* bla-?-blubb
    $ ls
    test};{bla#?"blubb  bla-test};{bla#?"blubb-blubb
    


    添加后缀的一些早期版本的脚本:

    类似于@WinEunuuchs2Unix 答案,但我认为更灵活且不解析ls:

    cps(){ S="$1"; shift; printf '%s\0' "$@" | xargs -0 -I{} cp -abfS "$S" {} {}; }
    

    把它放在你的.bashrc.

    用法:

    cps SUFFIX FILES...
    Example: cps .bak gmail-meta3*
    

    或者,后缀作为最后一个参数(via和via):

    cps(){ S="${@: -1}"; printf '%s\0' "${@:1:$#-1}" | xargs -0 -I{} cp -abfS "$S" {} {}; }
    

    用法:

    cps FILES... SUFFIX
    Example: cps gmail-meta3* .bak
    

    • 4
  8. Dan
    2019-06-27T06:44:13+08:002019-06-27T06:44:13+08:00

    实现您的要求的另一种方法是将文件复制到临时目录并使用rename命令重命名它们。

    $ mkdir backup
    $ cp filename* /tmp/rename-backup/
    $ rename 's/(filename.*)/$1.bak/' /tmp/rename-backup/*
    $ mv /tmp/rename-backup/* ./
    

    如果你需要它作为脚本,你可以像这样使用它

    cps () {
        mkdir -p /tmp/rename-backup/
        cp "$1"* /tmp/rename-backup/
        rename "s/($1.*)/\$1.$2/" /tmp/rename-backup/*
        mv "/tmp/rename-backup/$1"*".$2" .
    }
    

    你可以像这样使用它:

    cps file bak
    

    这是一个例子

    $ ls -l
    total 0
    -rw-r--r--  1 danny  danny  0 Jun 26 16:23 file a
    -rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ab
    -rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ac
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename1
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename2
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename3
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename4
    $ cps file bak
    $ ls -l
    total 0
    -rw-r--r--  1 danny  danny  0 Jun 26 16:23 file a
    -rw-r--r--  1 danny  danny  0 Jun 26 16:41 file a.bak
    -rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ab
    -rw-r--r--  1 danny  danny  0 Jun 26 16:41 file ab.bak
    -rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ac
    -rw-r--r--  1 danny  danny  0 Jun 26 16:41 file ac.bak
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename1
    -rw-r--r--  1 danny  danny  0 Jun 26 16:41 filename1.bak
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename2
    -rw-r--r--  1 danny  danny  0 Jun 26 16:41 filename2.bak
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename3
    -rw-r--r--  1 danny  wheel  0 Jun 26 16:41 filename3.bak
    -rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename4
    -rw-r--r--  1 danny  danny  0 Jun 26 16:41 filename4.bak
    
    • 2

相关问题

  • 如何从命令行仅安装安全更新?关于如何管理更新的一些提示

  • 如何从命令行刻录双层 dvd iso

  • 如何从命令行判断机器是否需要重新启动?

  • 文件权限如何工作?文件权限用户和组

  • 如何在 Vim 中启用全彩支持?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve