【问题标题】:Wildcard on mv folder destinationmv 文件夹目标上的通配符
【发布时间】:2018-05-26 01:13:12
【问题描述】:

我正在编写一小段代码,用于检查特定文件夹中超过 4gb 的 .mov 文件,并按名称(不带扩展名)将其写入 log.txt 文件。然后,我将名称逐行读取到 while 循环中,这表明一些归档和复制命令。

考虑一个名为 abcdefg.mov(新)的文件和一个名为 abcdefg_20180525(

从 log.txt 中读取文件名时,我剥离扩展名以存储变量“abcdefg”($in1),并使用该变量在其他位置找到 包含的文件夹开头的匹配字符串。

我的问题是 mv 命令似乎支持“源”字符串中的通配符,但不支持“目标”字符串。

比如我会写;

mv -f /Volumes/Myshare/SourceVideo/$in1*/$in1.mov /Volumes/Myshare/Archive

但是,目标上的通配符不能以相同的方式工作。例如;

mv -f /Volumes/Myshare/Processed/$in1.mov Volumes/Myshare/SourceVideo/$in1*/$in1.mov

这里有不涉及使用其他方法的简单修复吗?

为任何帮助干杯。

【问题讨论】:

  • 目的地中的通配符将是真正的掷骰子。你怎么能确定文件会在哪里结束?
  • 是的,我可以看到在某些情况下会出现问题,但我知道在我的情况下,基本名称总是唯一的,不可能 100% 匹配。它只是一个临时位置,因此一次只有 35-50 个文件夹......

标签: bash shell wildcard move


【解决方案1】:

mv 接受单个目标路径。假设$in1abcdfg,并且$in1* 扩展为abcdefg_20180525abcdefg_20180526。然后是命令

mv -f /dir1/$in1 /dir2/$in1*/$in1.mov

将等同于:

mv -f /dir1/abcdefg.mov /dir2/abcdefg_20180526/abcdefg.mov
mv -f /dir1/abcdefg.mov /dir2/abcdefg_20180526/abcdefg.mov
mv -f /dir2/abcdefg_20180525/abcdefg.mov /dir2/abcdefg_20180526/abcdefg.mov

此外,由于目标文件在所有三种情况下都相同,因此前两个文件将被第三个文件覆盖。

【讨论】:

  • 是的,肯定会看到问题出在哪里,但 100% 肯定它永远不会成为问题(在我的场景中),因为文件名都是唯一的,并且存储库只是临时的,不断被刷新为新文件夹移入。我很惊讶它以这种方式受到限制,应该能够基于理解所涉及的风险并使用最佳判断进行编码,而不是因为在某些情况下可能会出错而受到限制......
【解决方案2】:

您应该创建一个精确的列表并进行精确的复制,而不是使用通配符。

这就是我可能会做的,在具有完整路径信息的文件中生成结果列表,然后在另一个函数中读取这些结果。我本可以使用数组,但我想保持简单。该脚本的底部是一个函数调用,用于扫描 EXT mp4 文件(不区分大小写),然后将结果写入 tmp 中的文件。然后脚本在另一个函数中从该文件中读取结果并执行一些操作(mv 等)。请注意,如果函数令人困惑,您只需删除函数名称 { } 和名称调用,它就会再次成为普通脚本。功能真的好用,学会爱吧!

#!/usr/bin/env bash
readonly SIZE_CHECK_LIMIT_MB="10M"
readonly FOLDER="/tmp"
readonly DESTINATION_FOLDER="/tmp/archive"
readonly SAVE_LIST_FILE="/tmp/$(basename $0)-save-list.txt"
readonly EXT="mp4"
readonly CASE="-iname"  #change to -name for exact ext type upper/lower

function find_files_too_large() {

    > ${SAVE_LIST_FILE}
   find "${FOLDER}" -maxdepth 1 -type f "${CASE}" "*.${EXT}" -size +${SIZE_CHECK_LIMIT_MB} -print0 | while IFS= read -r -d $'\0' line ; do
        echo "FOUND => $line"
        echo "$line" >> ${SAVE_LIST_FILE}
    done

}

function archive_large_files() {

    local read_file="${SAVE_LIST_FILE}"
    local write_folder="$DESTINATION_FOLDER"

    if [ ! -s "${read_file}" ]  || [ ! -f "${read_file}" ] ;then
        echo "No work to be done ... "
        return
    fi

    while IFS= read -r line ;do
        echo "mv $line $write_folder" ;sleep 1
    done < "${read_file}"

}

# MAIN (this is where the script starts) We just call two functions.
find_files_too_large
archive_large_files

【讨论】:

    【解决方案3】:

    我认为,最初将文件名更改为文件夹名称可能更容易。所以 abcdefg.mov 就是 abcdefg_timestamp.mov。在将文件名复制到正确的位置后,我总是可以很容易地从文件名中删除时间戳。我希望我有一个小的语法问题,但我认为没有简单的方法可以做我认为我可以做的事情......

    【讨论】:

      【解决方案4】:

      我认为您对通配符在这里的工作方式有一个基本的误解。 mv 命令根本不支持通配符;在将所有通配符作为通配符传递给mv 命令之前,shell 会将它们扩展为匹配文件的列表。此外,mv 命令不知道它获得的参数列表是否来自通配符,并且 shell 不知道该命令将如何处理它们。例如,如果您运行命令grep *grep 命令只会获取当前目录中的文件名列表作为参数,并将其中的第一个视为正则表达式模式(因为这是第一个grep 的参数是)搜索其余文件。如果你运行mv *(注意:不要这样做!),它会将除最后一个文件名之外的所有文件名解释为源,并将最后一个文件名解释为目标。

      我认为还有另一个混淆来源:当 shell 扩展包含通配符的字符串时,它会尝试将 整个内容 与现有文件和/或目录匹配。因此,当您使用Volumes/Myshare/SourceVideo/$in1*/$in1.mov 时,它会在匹配目录中查找已存在的文件; AIUI 文件还没有,没有匹配。在这种情况下,它所做的是将包含原始(未扩展)通配符的字符串作为参数传递给mv,它会查找那个确切的名称,找不到它,并给你一个错误.

      (顺便说一句,该模式的前面是否应该有一个“/”?我假设如下。)

      如果我对情况的理解正确,您也许可以使用这个:

      mv -f /Volumes/Myshare/Processed/$in1.mov /Volumes/Myshare/SourceVideo/$in1*/
      

      由于第二个字符串中没有提供文件名,因此它不会查找具有该名称的现有文件,只查找具有正确前缀的目录; mv 会自动保留源文件名。

      但是,我会回应@Sergio 关于多场比赛造成混乱的警告。在这种情况下,它不会覆盖文件(好吧,它可能会,但出于其他原因),但如果它获得多个匹配的目标目录,它将把除最后一个以外的所有目录移动到最后一个(连同你想要的文件)移动)。你说你 100% 确定这不会是一个问题,但根据我的经验,这意味着至少有 50% 的机会你从未想过的事情会继续发生并让它发生。例如,$in1 是否有可能最终为空,或者包含一个空格,或者...?

      说到空格,我还建议对所有变量引用进行双引号。你想要双引号内的变量,但它们外面的通配符(或者它们不会被扩展),像这样:

      mv -f "/Volumes/Myshare/Processed/$in1.mov" "/Volumes/Myshare/SourceVideo/$in1"*/
      

      【讨论】:

      • 谢谢!我会试一试。你是对的,墨菲定律总是起作用……很可能会出现问题。我会尝试你的代码只是因为我想让它工作,但是我会考虑一种更安全的方法,比如在链的开头用文件夹名标记文件名,然后很容易找到匹配的文件夹结束。
      猜你喜欢
      • 1970-01-01
      • 2014-06-06
      • 2013-07-09
      • 2019-07-25
      • 2016-10-14
      • 1970-01-01
      • 2019-02-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多