mv文件夹目的地上的通配符

时间:2018-05-26 01:13:12

标签: bash shell wildcard move

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

考虑一个名为abcdefg.mov(new)的文件和一个名为abcdefg_20180525(< - * underscore timestamp)的相应文件夹,该文件夹还包含一个名为abcedfg.mov(old)的文件。

当从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

这里是否有一个简单的解决方法,并不涉及使用其他方法?

欢呼任何帮助。

4 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:0)

您应创建精确列表并执行精确复制,而不是使用通配符。

这是我可能会做的,在具有FULL路径信息的文件中生成结果列表,然后在另一个函数中读取这些结果。我可以使用数组,但我想保持简单。在此脚本的底部是一个函数调用,用于扫描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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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

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

(顺便说一下,如果有一个&#34; /&#34;在该模式的前面?我假设如下。)

如果我理解了这种情况,您可以使用它:

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"*/