【问题标题】:Splitting a file in a shell script adds unwanted newlines在 shell 脚本中拆分文件会添加不需要的换行符
【发布时间】:2021-11-02 19:39:55
【问题描述】:

我需要处理一个长文本文件,将其拆分为许多较小的文件。我有一个单程 while - read - done 循环,当匹配一行时,表示新输出文件的开始。在输入文件中,匹配的行总是以换行符开头。

我的问题是输出文件(除了最后一个)被换行符扩展。我在这个简短的例子中重现了这个问题。

#!/bin/zsh

rm inputfile outputfile1 outputfile2
IFS=''
printf "section1\nsection1end\n\nsection2\nsection2end\n" >inputfile

echo "  open outputfile1"
exec 3<> outputfile1
counter=1
IFS=$'\n'

while IFS= read line; do

    if [[ "$line" == "section2" ]]; then
        echo "  Matched start of section2. Close outputfile1 and open outputfile2"
        exec 3>&-
        exec 3<> outputfile2
    fi
    echo "$line" >&3
    echo $counter $line
    let "counter = $counter + 1"
done <inputfile
echo "  Close outputfile2"
exec 3>&-

echo
unset IFS
echo `wc -l inputfile`
echo `wc -l outputfile1`
echo `wc -l outputfile2`
echo "  The above should show 5, 2, 2 as desired number of newlines in these files."

哪些输出:

  open outputfile1
1 section1
2 section1end
3
  Matched start of section2. Close outputfile1 and open outputfile2
4 section2
5 section2end
  Close outputfile2

5 inputfile
3 outputfile1
2 outputfile2
  The above should show 5, 2, 2 as desired number of newlines in these files.

【问题讨论】:

  • 命令行实用程序拆分是否能够执行您想要的操作?
  • 我的实际代码有一系列扩展的正则表达式来检测部分更改 - 我认为我无法拆分以使用这些模式。
  • @kometen - 想了很多,我尝试用 ERE 拆分文件,然后必须移动并重命名生成的文件。正则表达式匹配出现在空行之后的行。 ksh split -p "^[## Foreword|## [0-9]+\.|## Appendix [0-9]+|### [0-9]+.[0-9]+\.]" draft6.md 生成了370个文件,都是最后一个,最后有两个空行!哦,好吧。
  • 您可能需要重新命名。如果我遵循正确,shell 脚本不会添加不需要的换行符,它是 retaining 不需要的换行符。换行符出现在原始输入中。
  • 我在下面的答案中添加了一些zsh 选项,但是使用awk 脚本执行此操作可能会更好,例如像这里的示例 5:theunixschool.com/2012/06/…

标签: zsh ifs


【解决方案1】:

选项 1

去掉所有空行。这仅在您不需要在部分中间保留任何空行时才有效。 变化:

    echo "$line" >&3

收件人:

    [[ -n "$line" ]] && echo "$line" >&3

选项 2

使用命令替换重写每个文件以修剪任何尾随换行符。最适合短文件。变化:

        exec 3>&-
        exec 3<> outputfile2

收件人:

        exec 3>&-
        data=$(<outputfile1)
        echo "$data" >outputfile1
        exec 3<> outputfile2

选项 3

让循环写入前一次迭代的行,然后在开始新文件时不要写入前一个文件的最后一行:

#!/bin/zsh

rm inputfile outputfile1 outputfile2
IFS=''
printf "section1\nsection1end\n\nsection2\nsection2end\n" >inputfile

echo "  open outputfile1"
exec 3<> outputfile1
counter=1
IFS=$'\n'

priorLine=MARKER
while IFS= read line; do
    if [[ "$line" == "section2" ]]; then
        echo "  Matched start of section2. Close outputfile1 and open outputfile2"
        exec 3>&-
        exec 3<> outputfile2
    elif [[ "$priorLine" != MARKER ]]; then
        echo "$priorLine" >&3
    fi
    echo $counter $line
    let "counter = $counter + 1"
    priorLine="$line"
done <inputfile
echo "$priorLine" >&3
echo "  Close outputfile2"
exec 3>&-

echo
unset IFS
echo `wc -l inputfile`
echo `wc -l outputfile1`
echo `wc -l outputfile2`
echo "  The above should show 5, 2, 2 as desired number of newlines in these files."

【讨论】:

  • 谢谢@Gairfowl - 选项二对我有用。输入文件有很多必需的空行(它用于将大量的降价文档分成章节) - 所以不会使用选项 1。选项三是我试图避免的 - 跟踪先前的行状态并不是一个干净的解决方案。 选项 2 - 很棒 - 只需在文件关闭后重写文件即可摆脱虚假行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
相关资源
最近更新 更多