【发布时间】:2011-05-23 23:41:47
【问题描述】:
我运行了一个脚本,它在一个目录中生成了大约 10k 个文件。我刚刚发现脚本中有一个错误导致某些文件名带有回车符(可能是'\n'字符)。
我想运行 sed 命令从文件名中删除回车。
任何人都知道要传递给 sed 以按照所述方式清理文件名的参数吗?
我正在运行 Linux (Ubuntu)
【问题讨论】:
我运行了一个脚本,它在一个目录中生成了大约 10k 个文件。我刚刚发现脚本中有一个错误导致某些文件名带有回车符(可能是'\n'字符)。
我想运行 sed 命令从文件名中删除回车。
任何人都知道要传递给 sed 以按照所述方式清理文件名的参数吗?
我正在运行 Linux (Ubuntu)
【问题讨论】:
其实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
这确实有效。
【讨论】:
我不知道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', '');")
【讨论】:
\n 和\r 之外,没有其他字符会导致换行。它可能只是你的文件管理器......
您没有得到任何纯-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
【讨论】:
如果你的文件名中没有空格,你可以这样做:
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。
【讨论】:
#!/bin/sh 兼容的答案:)
编辑:如果你真的想要 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 更容易理解)。
sed。使用起来容易得多。
sed 的难点在于它将换行符视为一个全新的输入行的开始。我的sed 版本只是从输入中删除空行。