【问题标题】:linux wildcard usage in cp and mvcp和mv中的linux通配符使用
【发布时间】:2016-06-13 00:29:48
【问题描述】:

我正在编写一个脚本来处理 20 个文件。它们都位于不同的目录中。我有部分文件名。

  1. 在日志目录中,File1_Date_time.err 更改为 File1__Date_time_orig.err
  2. cd ../scripts/
  3. sh 文件.sh

File1 目录为 /data/data1directory/Sample_File1/logs/File1_Data_time.err
File2目录为/data/data2directory/Sample_File2/logs/File2_Data_time.err
.....

我的脚本看起来像这样。 (runrunrun.sh)

#!/bin/bash
INPUT=$1
mv /data/*/Sample_*/logs/*_Data_time.err /data/*/Sample_*/logs/*_Data_time_orig.err
cp /data/*/Sample_*/scripts/*.sh /data/*/Sample_*/scripts/*_orig.sh
sh /data/*/Sample_*/scripts/*_orig.sh

在运行它时,我试过了。
./runrunrun.sh 文件1
. runrunrun.sh 文件 1
sh runrunrun.sh 文件1

mv: 无法移动 /data/data1directory/Sample_File1/logs/File1_Data_time.err /data/*/Sample_*/logs/*_Data_time_orig.err: 没有这样的文件或目录 cp也得到了类似的反馈

我做得对吗?

谢谢!

【问题讨论】:

  • mvcp没有通过您正在编写的通配符,如果这些通配符有任何有效的扩展。相反,它们被传递通过运行这些扩展创建的文字文件名。因此,由于他们不知道输入名称中使用的文字通配符,因此他们不可能将输入名称中的 * 映射到输出名称中的 *
  • 如果你想编写重命名工具,BashFAQ #30 是一个不错的起点:mywiki.wooledge.org/BashFAQ/030
  • 顺便说一句,sh foo.sh 非常危险,除非您绝对确定该脚本以 #!/bin/sh 而不是 #!/bin/bash#!/bin/ksh、@987654333 开头@, 等等;否则,它可能会使用错误的解释器。

标签: linux shell cp mv


【解决方案1】:

使用 awk 和 sed

使用 ls 过滤,使用 awk 为每条记录构建移动命令,最后的 sed 'e' 将执行该命令。

ls  *.avro  | awk ' { print "mv "$1" aa_"$1 }' | sed 'e'

首先尝试不使用 sed -- 一旦您知道您的命令显示正确,请添加 sed。

【讨论】:

    【解决方案2】:

    find 命令可以非常简洁地用于您想要对通配符(或更复杂的)文件名匹配执行操作的简单情况。下面的技术可以提交到内存中......几乎!

    这通过让find 命令在它找到的每个文件名上运行另一个命令来工作。您可以使用echo 代替/在mv 前面来试运行此示例。

    如果我们想将当前目录中名称以“report”开头的所有文件移动到另一个名为“reports”的并行目录:

    find . -name "report*.*" -exec mv '{}' ../reports/ \;
    

    通配符字符串必须用引号括起来,标记“找到”的文件名的 {} 必须用引号括起来,最后的分号必须被转义 - 所有这些都是由于对这些字符的 Bash/shell 处理。

    查看find 的手册页以了解更多用途:https://linux.die.net/man/1/find

    【讨论】:

    • 如果多个文件的文件名相同,这个解决方案似乎会覆盖目标中的文件。如何复制整个文件夹结构?
    • 第一个答案涵盖了我的情况。我还使用 cp --parents ============================= for f in ./*/*20220202.csv;做 cp -rfv --parents "$f" "/projects/drprojects/evmc/tempo4/" 完成
    • 代码只是一个例子。原来的问题也有这个问题。问一个单独的问题,或者解决它!
    【解决方案3】:

    这是我用的,写起来很快,记起来也很快

    复制:

    ls -1 *.txt | xargs -L1 -I{} cp {} {}.old 
    

    搬家:

    ls -1 *.txt | xargs -L1 -I{} mv {} {}.old 
    

    解释:

    xargs(1) -L1 -I{}  
    

    从标准输入构建和执行命令行

    -L max-lines
           Use  at most max-lines nonblank input lines per command line.  Trailing blanks cause an input line
           to be logically continued on the next input line.  Implies -x.
    
    -I replace-str
           Replace occurrences of replace-str in the initial-arguments with names read from  standard  input.
           Also,  unquoted  blanks  do  not  terminate  input  items;  instead  the  separator is the newline
           character.  Implies -x and -L 1.
    

    基本上与-L1 一起发送参数,-I{} 使{} 成为占位符

    【讨论】:

    • 带有有趣文件名的越野车。一般来说, xargs 只有在 NUL 分隔的输入和 -0 参数下才是安全的;默认行为将输入拆分为空格,而不仅仅是换行符(尽管换行符也不安全,因为它们在文件名中是允许的);将引号字符视为语法而不是文字数据;否则通常会输入。
    【解决方案4】:

    让我们来谈谈通配符的工作原理。

    cp *.txt foo
    

    如果存在与该 glob 匹配的任何文件,则实际上不会使用参数 *.txt 调用 cp。相反,它运行如下:

    cp a.txt b.txt c.txt foo
    

    类似

    mv *.txt *.old
    

    ...不可能知道该怎么做,因为当它被调用时,它看到的是:

    mv a.txt b.txt c.txt *.old
    

    或者,更糟糕的是,如果您已经拥有一个名为 z.old 的文件,它会看到:

    mv a.txt b.txt c.txt z.old
    

    因此,您需要使用不同的工具。考虑:

    # REPLACES: mv /data/*/Sample_*/logs/*_Data_time.err /data/*/Sample_*/logs/*_Data_time_orig.err
    for f in /data/*/Sample_*/logs/*_Data_time.err; do
      mv "$f" "${f%_Data_time.err}_Data_time_orig.err"
    done
    
    # REPLACES: cp /data/*/Sample_*/scripts/*.sh /data/*/Sample_*/scripts/*_orig.sh
    for f in /data/*/Sample_*/scripts/*.sh; do
      cp "$f" "${f%.sh}_orig.sh"
    done
    
    # REPLACES: sh /data/*/Sample_*/scripts/*_orig.sh
    for f in /data/*/Sample_*/scripts/*_orig.sh; do
      if [[ -e "$f" ]]; then
        # honor the script's shebang and let it choose an interpreter to use
        "$f"
      else
        # script is not executable, assume POSIX sh (not bash, ksh, etc)
        sh "$f"
      fi
    done
    

    这使用parameter expansion 在添加新名称之前去除旧名称的尾部。

    【讨论】:

    • 从 2020 年开始,GNU bash 5.0 及更高版本不再是这种情况
    • @user164863,请提供相反的演示。 mvcp 不是 bash 本身的一部分,它们由您的操作系统供应商提供,并且 glob 在调用之前已经扩展;这些都没有改变。
    【解决方案5】:

    试试这个:

    改变这些:

    zc_cd_delim_01.csv
    zc_cd_delim_04.csv
    

    进入这些:

    zc_cd_delim_113_01.csv
    zc_cd_delim_113_04.csv
    

    命令行:

    for f in zc_cd_delim_??.csv; do var1=${f%%??.*}; 
        mv $f "${var1}113_${f#$var1}"; 
    done
    

    【讨论】:

    • mv "$f",而是 -- 如果?? 匹配带有空格的文件名,或者IFS 包含在名称中找到的字符(即_),否则行为可能会令人惊讶.
    • 顺便说一句,我有点不清楚这如何适用于手头的问题——c_cd_delim_??.csv 在我看来并不像 OP 用作示例的模式之一他们想要匹配的东西。您介意编辑以使问题的适用性更清晰吗?
    猜你喜欢
    • 2012-09-13
    • 2014-09-03
    • 2011-11-19
    • 2020-08-24
    • 2011-03-29
    • 1970-01-01
    • 2017-12-07
    • 2014-03-31
    • 1970-01-01
    相关资源
    最近更新 更多