我正在编写一小段代码,用于检查超过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
这里是否有一个简单的解决方法,并不涉及使用其他方法?
欢呼任何帮助。
答案 0 :(得分:1)
mv
接受单个目标路径。假设$in1
为abcdfg
,$in1*
扩展为abcdefg_20180525
和abcdefg_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"*/