编者按:这个问题始终是关于循环效果 ,但是原始标题引导了一些回答者和选民 - 相信它是关于如何删除Windows行结尾。
下面的bash循环只是删除了Windows行结尾并将它们转换为unix并且似乎正在运行,但速度很慢。输入文件很小(4个文件,范围从167字节 - 1 kb),并且都是相同的结构(名称列表),唯一不同的是长度(即一些文件是10个名称,其他文件是50)。是否需要花费超过15分钟才能使用Xeon处理器完成此任务?谢谢:))
for f in /home/cmccabe/Desktop/files/*.txt ; do
bname=`basename $f`
pref=${bname%%.txt}
sed 's/\r//' $f - $f > /home/cmccabe/Desktop/files/${pref}_unix.txt
done
输入.txt文件
AP3B1
BRCA2
BRIP1
CBL
CTC1
修改
这不是重复,因为我更多地询问为什么使用bash
删除Windows行结尾的sed
循环运行得如此之慢。我不是故意暗示如何删除它们,是在寻求可能加速循环的想法,而且我得到了很多。谢谢 :)。我希望这会有所帮助。
答案 0 :(得分:6)
使用实用程序dos2unix
和unix2dos
在unix和windows样式行结尾之间进行转换。
答案 1 :(得分:5)
你的'sed'命令看起来不对。我认为结尾$f - $f
应该只是$f
。以书面形式运行脚本会在我的系统上挂起很长时间,但进行此更改会导致它几乎立即完成。
当然,最佳答案是使用dos2unix
,它旨在处理这个问题:
cd /home/cmccabe/Desktop/files
for f in *.txt ; do
pref=$(basename -s '.txt' "$f")
dos2unix -q -n "$f" "${pref}_unix.txt"
done
答案 2 :(得分:4)
这对我来说总是有用的:
perl -pe 's/\r\n/\n/' inputfile.txt > outputfile.txt
答案 3 :(得分:1)
您可以按照前面的说明使用dos2unix
或使用这个小sed
:
sed 's/\r//' file
答案 4 :(得分:1)
Bash中的性能指标是通常避免循环,特别是那些在每次迭代中调用一个或多个外部实用程序的循环。
以下是使用 单 GNU awk
命令的解决方案:
awk -v RS='\r\n' '
BEGINFILE { outFile=gensub("\\.txt$", "_unix&", 1, FILENAME) }
{ print > outFile }
' /home/cmccabe/Desktop/files/*.txt
-v RS='\r\n'
将CRLF设置为输入记录分隔符,并且由于保留ORS
,输出记录分隔符的默认值为\n
,只需< em>打印每个输入行将使用\n
终止它。BEGINFILE
块;在其中,gensub()
用于在手头输入文件的_unix
后缀之前插入.txt
以形成输出文件名。{print > outFile}
只是将\n
- 终止的行打印到手头的输出文件中。 注意使用多个字符。 RS
值,BEGINFILE
块和gensub()
函数是POSIX标准的GNU扩展。
从OP的sed
解决方案切换到基于GNU awk
的解决方案是必要的,以便提供既简单又快速的单命令解决方案。
或者,这是一个依赖dos2unix
转换Window line-endings的解决方案(例如,您可以在基于Debian的系统上安装dos2unix
sudo apt-get install dos2unix
) ; 除了要求dos2unix
之外,它应该适用于大多数平台(不需要 GNU 实用程序):
dos2unix
- 这应该很快,因为不涉及对basename
的调用;改为使用Bash-native参数扩展。dos2unix
来处理所有文件。# cd to the target folder, so that the operations below do not need to handle
# path components.
cd '/home/cmccabe/Desktop/files'
# Collect all *.txt filenames in an array.
inFiles=( *.txt )
# Derive output filenames from it, using Bash parameter expansion:
# '%.txt' matches '.txt' at the end of each array element, and replaces it
# with '_unix.txt', effectively inserting '_unix' before the suffix.
outFiles=( "${inFiles[@]/%.txt/_unix.txt}" )
# Create an interleaved array of *input-output filename pairs* to be passed
# to dos2unix later.
# To inspect the resulting array, run `printf '%s\n' "${fileArgs[@]}"`
# You'll see pairs like these:
# file1.txt
# file1_unix.txt
# ...
fileArgs=(); i=0
for inFile in "${inFiles[@]}"; do
fileArgs+=( "$inFile" "${outFiles[i++]}" )
done
# Now, use a *single* invocation of dos2unix, passing all input-output
# filename pairs at once.
dos2unix -q -n "${fileArgs[@]}"