我正在尝试编写一个简单的bash脚本,允许我重命名一些格式不佳的电视节目文件名(并且不会被xbmc选中)。我能够获得awk命令打印出我想要输出的内容,但是只要我将它放入反引号(或重音字符)中,这样我就可以合并mv命令,它就会出错。
我工作的awk命令如下(在它上面有一个简单的for循环来遍历目录中的所有文件)。
echo $i | awk -F" " '{print $1 "\\ -\\ S0" $3 "E" $5 ".avi"}'
但是,当我向其添加mv命令时,
mv $i `echo $i | awk -F" " '{print $1 "\\ -\\ S0" $3 "E" $5 ".avi"}'`
以下内容出错。
awk: warning: escape sequence `\ ' treated as plain ` '
据我所知,我需要反斜杠才能使mv命令正常工作。
文件名的输入格式为
Showname Season 1 Episode 01 - Episode Title.avi
Show Name Season 1 Episode 01 - Episode Title.avi
我希望它是
Showname - S01E01 - Episode Title.avi
Show Name - S01E01 - Episode Title.avi
我不太担心包含的剧集标题(我找不到任何简单的方法来包含所有额外的字段,我还有另一个程序,我用来移动并命名我的所有文件,无论如何将把标题那里)。有些节目的名字中有两个单词(因此它可能是Show Name),所以我的计划是手动调整脚本以使用各种字段。
有没有关于如何让awk正常使用文件名的建议,以防止在我使用“反引号”时出现错误?
答案 0 :(得分:4)
请注意,由于您的文件名包含空格(或者至少是有趣的文件名),您应该在"$i"
命令和{{1}中使用mv
周围的双引号}}。你侥幸逃脱了它。在echo中如果文件名中只有单个空格且没有制表符或换行符,但是如果不将其用双引号括起来并且它包含两个相邻的空格或前导空格,则会销毁文件名,或者尾随空格,或...通常,使用echo
而不是后引号。
通过提供一些(一个或两个)样本输入文件名以及预期的相应输出文件名,可以改善您的问题。我们所能说的是,当你使用空格分割时($(...)
几乎不需要),你至少有5个文件名部分,其中只保留第一个,第三个和第五个。您可能在输出中生成反斜杠以保留名称中的空格,而不是因为您认为文件名中的反斜杠是个好主意。 (也就是说,反斜杠不会出现在磁盘上的名称中。)
由于你有一个循环,我用-F" "
执行此操作的方式是:
awk
这样做有充分的理由。赋值在for file in *
do
name=$(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}')
mv "$file" "$name"
done
的输出中保留空格等(砍掉尾随的换行符,但这就是全部)。 awk
命令行是微不足道的,使用双引号来防止出现问题。
尝试:
mv
让你遇到麻烦,因为管道的输出被shell重新扫描并拆分,你必须防止分裂(因此原始代码中的反斜杠)并担心其他shell元字符(如果一个节目'例如,s名称中包含撇号。
但是,您可以将整个for file in *
do
mv "$file" $(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}')
done
括在双引号中,然后就可以了 - 我打算按照预期说出来'但实际上它并不像我预期的那样。但是使用$(...)
和bash
进行测试表明这有效:
ksh
外部双引号只是阻止shell扩展for file in *
do
mv "$file" "$(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}')"
done
的输出,使用$(...)
大大简化了生命。简单地用后引号替换$(...)
会产生各种问题;在反叛内部,你必须逃避各种各样的事情。但似乎$(...)
符号中的$(
会暂停当前双引号字符串搜索,并开始搜索结束$(...)
并使用' normal'解释中间的内容,得出所需的结果。
我认为两行(赋值加使用)更容易理解,但是这个带有双引号内复杂命令替换的版本也可以。
以下是一些测试代码,假设您当前目录中没有名为)
的目录(并且您在当前目录中具有写入权限):
spaced-out
当作为脚本(mkdir spaced-out
(
cd spaced-out
# Create files with spaces in the names
for file in "part1 x part2 y part3" "show1 a show2 b show3" \
" leader1 x leader2 y leader3 "
do
echo hello world > "$file"
done
ls
ls -l
# Rename the files
for file in *
do
mv "$file" "$(echo "$file" | awk '{print $1 " - S0" $3 "E" $5 ".avi"}')"
done
# Show results and clean up
ls -l
rm -f *
)
rmdir spaced-out
)运行时,它会生成:
bash rename.script
以 leader1 x leader2 y leader3 part1 x part2 y part3 show1 a show2 b show3
total 24
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 leader1 x leader2 y leader3
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 part1 x part2 y part3
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 show1 a show2 b show3
total 24
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 leader1 - S0leader2Eleader3.avi
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 part1 - S0part2Epart3.avi
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:02 show1 - S0show2Eshow3.avi
运行时,会生成:
bash -x rename.script
双倍行距文件名(可选地带有前导和/或尾随空格)通常是对声称使用包含空格的文件名的脚本进行的非常好的测试。此代码不管理包含换行符的文件名; + mkdir spaced-out
+ cd spaced-out
+ for file in '"part1 x part2 y part3"' '"show1 a show2 b show3"' '" leader1 x leader2 y leader3 "'
+ echo hello world
+ for file in '"part1 x part2 y part3"' '"show1 a show2 b show3"' '" leader1 x leader2 y leader3 "'
+ echo hello world
+ for file in '"part1 x part2 y part3"' '"show1 a show2 b show3"' '" leader1 x leader2 y leader3 "'
+ echo hello world
+ ls
leader1 x leader2 y leader3 part1 x part2 y part3 show1 a show2 b show3
+ ls -l
total 24
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 leader1 x leader2 y leader3
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 part1 x part2 y part3
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 show1 a show2 b show3
+ for file in '*'
++ echo ' leader1 x leader2 y leader3 '
++ awk '{print $1 " - S0" $3 "E" $5 ".avi"}'
+ mv ' leader1 x leader2 y leader3 ' 'leader1 - S0leader2Eleader3.avi'
+ for file in '*'
++ echo 'part1 x part2 y part3'
++ awk '{print $1 " - S0" $3 "E" $5 ".avi"}'
+ mv 'part1 x part2 y part3' 'part1 - S0part2Epart3.avi'
+ for file in '*'
++ echo 'show1 a show2 b show3'
++ awk '{print $1 " - S0" $3 "E" $5 ".avi"}'
+ mv 'show1 a show2 b show3' 'show1 - S0show2Eshow3.avi'
+ ls -l
total 24
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 leader1 - S0leader2Eleader3.avi
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 part1 - S0part2Epart3.avi
-rw-r--r-- 1 jleffler eng 12 Jul 6 08:03 show1 - S0show2Eshow3.avi
+ rm -f 'leader1 - S0leader2Eleader3.avi' 'part1 - S0part2Epart3.avi' 'show1 - S0show2Eshow3.avi'
+ rmdir spaced-out
脚本将一个名称视为两行输入,这不是他们想要的。它可以修复;它通常不值得麻烦,除非你需要你的脚本是绝对防弹的(例如,因为它是针对客户的 - 客户做了最糟糕的事情,带有换行符的文件名完全在他们的能力范围内,即使你自己也没做过。)
答案 1 :(得分:1)
试试这个:
for file in *
do
set -- $file
mv -- "$i" "$(printf "%s - %s %sE%s.avi" "$1" "$file" "$3" "$5")"
done
这是一个猜测 - 您需要显示您的输入和输出文件名实际上是什么样的,而不仅仅是一个无法转换它们的命令!
答案 2 :(得分:0)
好吧,经过更多的挖掘和玩弄后,我发现我可以用引号括起mv命令的整个目标,然后只需删除反斜杠。
然后我想出了一个不同的问题。有人说mv命令的目标不是目录。我知道它不是一个目录......我试图在这里重命名一些文件......(抱怨,发牢骚)
mv: target 'Showname - S01E01.avi' is not a directory
无论如何,经过更多的谷歌搜索我发现LinuxQuestions post这显然是由于文件名中的空格。我能够通过在脚本的开头添加以下内容来解决这个问题。
IFS='
'
现在它将我的文件重命名为一个不错的命名方案,以便其他程序/服务可以接收它们并正确添加它们