【问题标题】:How can I list all unique file names without their extensions in bash?如何在 bash 中列出所有不带扩展名的唯一文件名?
【发布时间】:2010-10-09 09:14:56
【问题描述】:

我有一个任务,我需要将一堆文件从一个目录移动到另一个目录。我需要同时移动具有相同文件名的所有文件(即 blah.pdf、blah.txt、blah.html 等),并且我可以每四分钟移动一组文件。我有一个简短的 bash 脚本,可以在这些时间间隔一次移动一个文件,但新的名称要求让我失望。

我的旧脚本是:
find ./ -maxdepth 1 -type f | while read line; do mv "$line" ~/target_dir/; echo "$line"; sleep 240; done

对于新的脚本,我基本上只需要替换 find ./ -maxdepth 1 -type f 带有唯一文件名的列表,没有扩展名。然后我可以将do mv "$line" ~/target_dir/; 替换为do mv "$line*" ~/target_dir/;

所以,说了这么多。什么是使用 bash 脚本获取没有文件名的唯一文件列表的好方法?我正在考虑使用正则表达式来获取文件名,然后将它们放入哈希中以获得唯一性,但我希望有一种更简单/更好/更快的方法。想法?

【问题讨论】:

    标签: bash


    【解决方案1】:

    一个奇怪的命名文件容忍单行可能是:

    find . -maxdepth 1 -type f -and -iname 'blah*' -print0 | xargs -0 -I {} mv {} ~/target/dir
    

    如果文件可以以多个前缀开头,则可以在 find 中使用逻辑运算符。例如,要移动 blah.* 和 foo.*,请使用:

    find . -maxdepth 1 -type f -and \( -iname 'blah.*' -or -iname 'foo.*' \) -print0 | xargs -0 -I {} mv {} ~/target/dir
    

    编辑

    评论后更新。

    我会这样做:

    find ./ -type f -printf '%f\n' | sed 's/\..*//' | sort | uniq | ( while read filename ; do find . -type f -iname "$filename"'*' -exec mv {} /dest/dir \; ; sleep 240; done )
    

    也许需要解释一下:

    • find ./ -type f -printf '%f\n': 查找所有文件并仅打印它们的名称,后跟换行符。如果不想查看子目录,可以用简单的ls 代替;
    • sed 's/\..*//':通过删除第一个点之后的所有内容来去除文件扩展名。 foo.tarfoo.tar.gz 都转换为 foo
    • sort | unique:对刚刚找到的文件名进行排序,去掉重复的;
    • (:打开一个子shell:
      • while read filename:读取一行并将其放入$filename变量中;
      • find . -type f -iname "$filename"'*' -exec mv {} /dest/dir \;:在当前目录 (find .) 中查找名称以 filename (-iname "$filename"'*',这也适用于名称中包含空格的文件) 中的值开头的所有文件 (-type f) 并执行mv 每个命令上的命令 (-exec mv {} /dest/dir \;)
      • sleep 240:睡觉
    • ):子shell结束。

    -maxdepth 1 作为参数添加到find,只要您认为符合您的要求。

    【讨论】:

    • 文件名并不总是'blah*'。那只是一个例子。它们根本不为人所知或硬编码。我需要获取所有唯一文件名的列表。因此,对于包含文件“blah.html、blah.txt、foo.jpg、foo.html”的文件夹,它应该输出“blah, foo”,然后我可以将其通过管道传输到移动 blah* 的脚本,然后foo* 4 分钟后。明白我的意思了吗?
    • 我会用另一条线编辑答案,但你已经回答了你自己的问题 :)
    • Crud,其实我刚试了一下,好像 do mv $line* 真的不起作用。有什么想法吗?
    • 我编辑了我的答案,我希望这是您正在寻找的解决方案。
    【解决方案2】:

    没关系,我很笨。有一个 uniq 命令。呃。新的工作脚本是:

    find ./ -maxdepth 1 -type f | sed -e 's/.[a-zA-Z]*$//' | uniq | while read line; do mv "$line*" ~/target_dir/; echo "$line"; sleep 240; done

    编辑:忘记代码和反斜杠上的结束标记。

    【讨论】:

    • 我很确定您需要将通配符放在引号之外(即mv "$line"* ...)才能使其正常工作。此外,您可能应该排除点文件(即添加 -not -name ".*" 到 find 命令)以防止它找到 ".somethingorother" -> "" -> mv ""* ... 这会很糟糕。
    猜你喜欢
    • 2014-05-12
    • 1970-01-01
    • 2022-12-14
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 2012-02-24
    • 2020-03-09
    • 1970-01-01
    相关资源
    最近更新 更多