KSH Shell 脚本 - 按行块处理文件
KSH Shell script - Process file by blocks of lines
我正在尝试在 KSH 环境中编写一个 bash 脚本,该脚本将遍历源文本文件并逐行处理它
到目前为止我已经想出了这段代码,尽管它似乎无限期地运行,因为 tail 命令不会 return 0 行如果被要求检索超出源文本文件中的行
i=1
while [[ `wc -l /path/to/block.file | awk -F' ' '{print }'` -gt $((i * 1000)) ]]
do
lc=$((i * 1000))
DA=ProcessingResult_$i.csv
head -$lc /path/to/source.file | tail -1000 > /path/to/block.file
cd /path/to/processing/batch
./process.sh #This will process /path/to/block.file
mv /output/directory/ProcessingResult.csv /output/directory/$DA
i=$((i + 1))
done
在启动上述脚本之前,我执行了一个手动操作 'first injection':head -$lc /path/to/source.file | tail -1000 > /path/to/temp.source.file
知道如何在处理完源文件的最后几行后停止脚本吗?
在此先感谢大家
看看man split
NAME
split - split a file into pieces
SYNOPSIS
split [OPTION]... [INPUT [PREFIX]]
-l, --lines=NUMBER
put NUMBER lines per output file
例如
split -l 1000 source.file
或者以提取第三个chunk为例(这里的1000不是行数,而是chunk的个数,或者一个chunk是source.file的1/1000)
split -nl/3/1000 source.file
条件说明:
[[ `wc -l /path/to/block.file | awk -F' ' '{print }'` -gt $((i * 1000)) ]]
也许它应该是 source.file 而不是 block.file,而且它在大文件上效率很低,因为它会在每次迭代时读取(计算文件的行数);行数可以存储在变量中,在标准输入上使用 wc 也可以防止使用 awk:
nb_lines=$(wc -l </path/to/source.file )
在 Nahuel 的推荐下,我能够像这样构建脚本:
i=1
cd /path/to/sourcefile/
split source.file -l 1000 SF
for sf in /path/to/sourcefile/SF*
do
DA=ProcessingResult_$i.csv
cd /path/to/sourcefile/
cat $sf > /path/to/block.file
rm $sf
cd /path/to/processing/batch
./process.sh #This will process /path/to/block.file
mv /output/directory/ProcessingResult.csv /output/directory/$DA
i=$((i + 1))
done
效果很好
如果您不想在开始处理每个块之前预先创建这么多临时文件,您可以尝试以下解决方案。它可以在处理大文件时节省很多space。
#!/usr/bin/ksh
range=
file=
b=0; e=0; seq=1
while true
do
b=$((e+1)); e=$((range*seq));
sed -n ${b},${e}p $file > ${file}.temp
[ $(wc -l ${file}.temp | cut -d " " -f 1) -eq 0 ] && break
## process the ${file}.temp as per your need ##
((seq++))
done
以上代码一次只生成一个临时文件。
您可以将范围(块大小)和文件名作为命令行参数传递给脚本。
example: extractblock.sh 1000 inputfile.txt
我正在尝试在 KSH 环境中编写一个 bash 脚本,该脚本将遍历源文本文件并逐行处理它
到目前为止我已经想出了这段代码,尽管它似乎无限期地运行,因为 tail 命令不会 return 0 行如果被要求检索超出源文本文件中的行
i=1
while [[ `wc -l /path/to/block.file | awk -F' ' '{print }'` -gt $((i * 1000)) ]]
do
lc=$((i * 1000))
DA=ProcessingResult_$i.csv
head -$lc /path/to/source.file | tail -1000 > /path/to/block.file
cd /path/to/processing/batch
./process.sh #This will process /path/to/block.file
mv /output/directory/ProcessingResult.csv /output/directory/$DA
i=$((i + 1))
done
在启动上述脚本之前,我执行了一个手动操作 'first injection':head -$lc /path/to/source.file | tail -1000 > /path/to/temp.source.file
知道如何在处理完源文件的最后几行后停止脚本吗?
在此先感谢大家
看看man split
NAME
split - split a file into pieces
SYNOPSIS
split [OPTION]... [INPUT [PREFIX]]
-l, --lines=NUMBER
put NUMBER lines per output file
例如
split -l 1000 source.file
或者以提取第三个chunk为例(这里的1000不是行数,而是chunk的个数,或者一个chunk是source.file的1/1000)
split -nl/3/1000 source.file
条件说明:
[[ `wc -l /path/to/block.file | awk -F' ' '{print }'` -gt $((i * 1000)) ]]
也许它应该是 source.file 而不是 block.file,而且它在大文件上效率很低,因为它会在每次迭代时读取(计算文件的行数);行数可以存储在变量中,在标准输入上使用 wc 也可以防止使用 awk:
nb_lines=$(wc -l </path/to/source.file )
在 Nahuel 的推荐下,我能够像这样构建脚本:
i=1
cd /path/to/sourcefile/
split source.file -l 1000 SF
for sf in /path/to/sourcefile/SF*
do
DA=ProcessingResult_$i.csv
cd /path/to/sourcefile/
cat $sf > /path/to/block.file
rm $sf
cd /path/to/processing/batch
./process.sh #This will process /path/to/block.file
mv /output/directory/ProcessingResult.csv /output/directory/$DA
i=$((i + 1))
done
效果很好
如果您不想在开始处理每个块之前预先创建这么多临时文件,您可以尝试以下解决方案。它可以在处理大文件时节省很多space。
#!/usr/bin/ksh
range=
file=
b=0; e=0; seq=1
while true
do
b=$((e+1)); e=$((range*seq));
sed -n ${b},${e}p $file > ${file}.temp
[ $(wc -l ${file}.temp | cut -d " " -f 1) -eq 0 ] && break
## process the ${file}.temp as per your need ##
((seq++))
done
以上代码一次只生成一个临时文件。 您可以将范围(块大小)和文件名作为命令行参数传递给脚本。
example: extractblock.sh 1000 inputfile.txt