【问题标题】:sed command to fix filenames in a directorysed 命令修复目录中的文件名
【发布时间】:2011-05-23 23:41:47
【问题描述】:

我运行了一个脚本,它在一个目录中生成了大约 10k 个文件。我刚刚发现脚本中有一个错误导致某些文件名带有回车符(可能是'\n'字符)。

我想运行 sed 命令从文件名中删除回车。

任何人都知道要传递给 sed 以按照所述方式清理文件名的参数吗?

我正在运行 Linux (Ubuntu)

【问题讨论】:

    标签: bash ubuntu sed


    【解决方案1】:

    其实sed是有办法使用的:

    carr='\n'                                        # specify carriage return
    files=( $(ls -f) )                               # array of files in current dir
    for i in ${files[@]}
    do 
        if [[ -n $(echo "$i" | grep $carr) ]]        # filenames with carriage return
        then
            mv "$i" "$(echo "$i" | sed 's/\\n//g')"  # move!
        fi
    done
    

    这确实有效。

    【讨论】:

      【解决方案2】:

      我不知道sed 会如何做到这一点,但这个python 脚本应该可以解决问题:。

      这不是sed,但我发现python 在执行以下操作时更容易使用:

      #!/usr/bin/env python
      
      import os
      
      files = os.listdir('.')
      
      for file in files:
        os.rename(file, file.replace('\r', '').replace('\n', ''))
        print 'Processed ' + file.replace('\r', '').replace('\n', '')
      

      它会从给定目录中的所有文件名中删除所有出现的 \r\n

      要运行它,请将其保存在某处,cd 到您的目标目录(包含要处理的文件),然后运行 ​​python /path/to/the/file.py

      另外,如果您打算进行更多批量重命名,请考虑Métamorphose。对于这些东西来说,这是一个非常好的和强大的 GUI。而且,它是免费的

      祝你好运!


      实际上,试试这个:cd 进入目录,输入python,然后粘贴到:

      exec("import os\nfor file in os.listdir('.'):\n  os.rename(file, file.replace('\\r', '').replace('\\n', ''))\n  print 'Processed ' + file.replace('\\r', '').replace('\\n', '')")
      

      是之前脚本的单行版本,不用保存。


      第 2 版,具有空间替换功能:

      #!/usr/bin/env python
      
      import os
      
      for file in os.listdir('.'):
        os.rename(file, file.replace('\r', '').replace('\n', '').replace(' ', '_')
        print 'Processed ' + file.replace('\r', '').replace('\n', '')
      

      这里是单行:

      exec("import os\nfor file in os.listdir('.'):\n  os.rename(file, file.replace('\\r', '').replace('\\n', '')replace(' ', '_'))\n  print 'Processed ' + file.replace('\\r', '').replace('\\n', '');")
      

      【讨论】:

      • @blender:感谢脚本。我运行它没问题,但文件名仍然跨越多行“分解”。哪个其他角色可能导致这种情况?显然 \\r 和 \\n 不是这里的罪魁祸首:(
      • 你确定不只是换行和空格吗?对我来说,长文件名沿空格分开。如果你愿意,我可以修改它以用下划线替换空格。也许这会有所帮助?
      • 我也发布了一个空间替换脚本。测试一下,也许这行得通?除了\n\r 之外,没有其他字符会导致换行。它可能只是你的文件管理器......
      • 这就是你的意思:img88.imageshack.us/img88/4416/screenshotvub.png?那只是 Nautilus 包装了这个名字。没有换行符,因此实际名称没有换行符。
      • @blender:不,它们绝对不是空格,并且包装不是由鹦鹉螺引起的。当我检查文件属性时,文件名包含一些出现中断的奇怪字符。如果我尝试将文件(它们是 CSV 文件)导入 OpenOffice,文本导入的标题如下所示:“this%0Dis%the%0Dfullname.csv” 其中 %0D 是导致文件名跨越多行。 HTH
      【解决方案3】:

      您没有得到任何纯-sed 答案的原因是基本上sed 编辑文件内容,而不是文件名;因此,所有使用 sed 的答案都会将文件名回显到管道(伪文件)中,使用sed 对其进行编辑,然后使用mv 将其转回文件名。

      由于 sed 已经发布,这里有一个纯 bash 版本,可以添加到您目前拥有的 Perl、Python 等脚本中:

      killpattern=$'[\r\n]' # remove both carriage returns and linefeeds
      for f in *; do
          if [[ "$f" == *$killpattern* ]]; then
              mv "$f" "${f//$killpattern/}"
          fi
      done
      

      ...但是由于${var//pattern/replacement} 在普通sh 中不可用(以及[[...]]),这里有一个使用sh-only 语法和tr 进行字符替换的版本:

      for f in *; do
          new="$(printf %s "$f" | tr -d "\r\n")"
          if [ "$f" != "$new" ]; then
              mv "$f" "$new"
          fi
      done
      

      【讨论】:

        【解决方案4】:

        如果你的文件名中没有空格,你可以这样做:

        for f in *$'\n'; do mv "$f" $f; done
        

        如果嵌入了换行符,它将不起作用,但它可以用于尾随换行符。

        如果一定要使用sed:

        for f in *$'\n'; do mv "$f" "$(echo "$f" | sed '/^$/d')"; done
        

        使用rename Perl 脚本:

        rename 's/\n//g' *$'\n'
        

        或 util-linux-ng 实用程序:

        rename $'\n' '' *$'\n'
        

        如果字符是回车符而不是换行符,请将上面出现的任何位置的 \n^$ 更改为 \r

        【讨论】:

        • 回到零;)我不知道为什么人们只是随机投反对票。可能刚刚获得特权的新手想要获得那个新徽章......
        • @Blender:谢谢。一款适合您的产品即将推出。
        • 现在就像一种货币形式。
        • 我投票赞成,因为您总是提供高质量的答案。即使我想看到一些#!/bin/sh 兼容的答案:)
        • @Blender:也许我们可以像第二人生等那样创造地下经济;)顺便说一句,我否认我曾经说过。
        【解决方案5】:

        编辑:如果你真的想要 sed,看看这个:

        这些方面的内容应该类似于下面的perl

        for i in *; do echo mv "$i" `echo "$i"|sed ':a;N;s/\n//;ta'`; done
        

        使用 perl,尝试以下方式:

        for i in *; do mv "$i" `echo "$i"|perl -pe 's/\n//g'`; done
        

        这将通过删除所有换行符来重命名当前文件夹中的所有文件。如果您需要递归,则可以改用find - 但请注意这种情况下的转义。

        【讨论】:

        • 没有人知道如何使用sed ;)
        • 我编辑添加了sed 解决方案-当我第一次回答时,我使用perl,因为sed 不是适合多行编辑的工具(正如您从该行中看到的那样 - perl 更容易理解)。
        • 嗯,我仍然更喜欢 Python 而不是 sed。使用起来容易得多。
        • @Blender:sed 的难点在于它将换行符视为一个全新的输入行的开始。我的sed 版本只是从输入中删除空行。
        猜你喜欢
        • 2021-04-28
        • 2021-08-27
        • 2023-04-09
        • 2011-12-05
        • 2015-08-16
        • 2021-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多