考虑到我很沮丧...我花了过去2个小时试图弄清楚如何让一个有管道的命令将输出泵送到for循环。关于我正在尝试遵循我的代码的快速故事。
我多年来一直在使用xbmc。然而,在我开始之后不久,我已经导出了我的库,结果证明它比它的价值更麻烦(特别是现在我正在使用包含在其中的文件夹和文件的集合命名方案)。我想删除xbmc添加的所有文件,所以我想我会编写一个脚本来删除所有必需的文件。然而,这就是我遇到问题的地方。
我正在尝试使用locate命令(因为它的速度),然后是grep(去除所有文件系统.tbn)和egrep(删除结果中创建的.actors文件夹xbmc),然后进行排序(虽然排序没有必要,我在调试期间添加了它,因此测试时的输出更好)。问题是只处理了第一个文件然后什么都没有。我在线阅读了很多,并发现bash为每个管道创建了一个新的子shell,当它完成一次循环时,变量现在已经死了。所以我做了更多关于如何解决这个问题,并且所有内容似乎都显示了我如何解决while循环问题,但没有任何for循环。
虽然我觉得自己能够胜任脚本编写,但我总是会遇到这样的问题,证明我还在学习基础知识。任何比我聪明的人的帮助都将不胜感激。
#!/bin/bash
for i in "$(locate tbn | grep Movies | egrep -v .actors | sort -t/ +4)"
do
DIR=$(echo $i | awk -F'/' '{print "/" $2 "/" $3 "/" $4 "/" $5 "/"}')
rm -r "$DIR*.tbn" "$DIR*.nfo" "$DIR*.jpg" "$DIR*.txt" "$DIR.actors"
done
阅读下面的回复后,我认为实现我想要的更好的路线如下。我喜欢任何有关新剧本的建议。我不想仅仅复制和粘贴@Charles Duffy的脚本,而是希望找到正确/最好的方式来做这个学习体验,因为总有一种更好,最好的方法来编写代码。
#!/bin/bash
for i in "*.tbn" "*.nfo" "*.jpg" "*.txt" "*.rar" #(any other desired extensions)
do
find /share/movies -name "$i" -not -path "/share/movies/.actors" -delete
done
我首先在-not -path
部分中删除xbmc从输出中放置在源目录(在本例中为/ share / movies)根目录的.actors文件夹,因此没有缩略图(.tbn)从那里删除,但我希望它们从/ share / movies中包含的任何其他目录中删除(如果它包含在特定的电影文件夹中,我想从.actors文件夹中删除缩略图)。 -delete
选项是因为在gnu.org页面中建议-delete
比调用/bin/rm
更好,因为不需要为rm进程分叉,这样可以提高效率,防止开销。
我很确定我希望引用for行中的项目,因此它是在find命令中使用的文字*.tbn
。为了让您了解目录结构,它非常简单。我想删除这些目录中的任何* .tbn * .jpg和* .nfo文件。
/share/movies/movie 1/movie 1.mkv
/share/movies/movie 1/movie 1.tbn
/share/movies/movie 1/movie 1.jpg
/share/movies/movie 1/movie 1.nfo
/share/movies/movie 2/movie 2.mp4
/share/movies/movie 2/movie 2.srt
/share/movies/movie 2/movie 2 (subs).rar
/share/movies/movie 3/movie 3.avi
/share/movies/movie 3/movie 3.tbn
/share/movies/movie 3/movie 3.jpg
/share/movies/movie 3/movie 3.nfo
/share/movies/movie 3/.actors/actor 1.tbn
/share/movies/movie 3/.actors/actor 2.tbn
/share/movies/movie 3/.actors/actor 3.tbn
答案 0 :(得分:2)
这只是一个引用问题。 "$(locate tbn | ...)"
是一个单词,因为引号会阻止分词。如果省略引号,它会变成多个单词,但文件路径中的空格将成为问题。
就个人而言,我会使用find
-exec
条款;它可能会慢locate
(locate
使用定期更新数据库,因此它会降低速度的准确性),但它会避免这种引用问题。
答案 1 :(得分:2)
通常在脚本中从locate
读取文件名是坏消息,除非您的locate
命令具有NUL分隔名称的选项(因为除NUL或/
以外的每个字符都有效在文件名中,换行实际上在文件名中有效,使得locate
的输出不明确)。那说:
#!/bin/bash
# ^^ -- not /bin/sh, since we're using bash-only features here!
while read -u 3 -r i; do
dir=${i%/*}
rm -r "$dir/"*".tbn" "$dir/"*".nfo" "$dir/"*".jpg" "$dir/"*".txt" "$dir/.actors"
done 3< <(locate tbn | grep Movies | egrep -v .actors)
注意*
不能如果要扩展它们,如果要扩展它们,即使目录名必须在里面双引号如果有空格&amp; c。在他们的名字。
一般来说,我同意@rici - 使用find
是迄今为止更强大的方法,尤其是与GNU扩展-execdir
一起使用以防止竞争条件被用于导致命令表现得不好。 (想想恶意用户在脚本运行时用符号链接替换目录到其他地方。)
答案 2 :(得分:1)
您编写的第二个脚本是一个改进。但是,仍有空间做得更好:
#!/bin/bash
exts=( tbn nfo jpg txt rar )
find_args=( )
for ext in "${exts[@]}"; do
find_args+=( -name "*.$ext" -o )
done
find /share/movies -name .actors -prune -o \
'(' "${find_args[@]:0:${#find_args[@]} - 1}" ')' -delete
这将构建如下命令:
find /share/movies -name .actors -prune -o \
'(' -name '*.tbn' -o -name '*.nfo' -o -name '*.jpg' \
-o -name '*.txt' -o -name '*.rar' ')' -delete
...因此一次性处理所有扩展。