首页 > 解决方案 > 从具有不同分隔符的文件中提取几个以空格分隔的字段到 Bash 中的另一个文件中

问题描述

我有一个来自第三方 Windows 软件的 Unicode/UTF-8 文本文件,其中包含大约十列数据。

标题行是制表符分隔的。但是,剩余的行是空格分隔的(不是制表符分隔的!)(如在 Notepad++ 或 TextWrangler 中打开文件时所见)。

以下是文件的前四行(例如):xyz(ns) z(cm) z-abs(cm) longitude- E latitude- N type_of_object description 728243.03 5993753.83 0 0 0 143.537779835969 -36.1741232463362 linestart DRIVEWAYGRAVEL 705993 72824203。 0 0 143.537768534943 -36.1741037476109 linestart DRIVEWAYGRAVEL 728242.26 5993756.11 0 0 0 143.537770619485 -36.1741028922293 linestart DRIVEWAYGRAVEL

x       y   z(ns)       z(cm)   z-abs(cm)   longitude-  E   latitude-   N   type_of_object  description
 728243.03     5993753.83    0             0             0             143.537779835969           -36.1741232463362           linestart     DRIVEWAYGRAVEL
 728242.07     5993756.02    0             0             0             143.537768534943           -36.1741037476109           line          DRIVEWAYGRAVEL
 728242.26     5993756.11    0             0             0             143.537770619485           -36.1741028922293           linestart     DRIVEWAYGRAVEL

(注意每行开头的空格,标题行除外)

这是 Notepad++ 中文件的屏幕截图,显示了分隔符

我正在尝试编写一个 Bash 脚本来重新格式化数据以导入不同的 Windows 程序。

(我意识到我可以在 Windows 命令行上执行此操作,但我没有这方面的经验,因此更愿意将文件复制到我的 Debian 机器上并在 Bash 中创建一个脚本。这意味着输入文件和输出文件需要与 Windows 兼容,但脚本本身显然是在 Linux 中运行的。)

我需要执行以下操作:

  1. 提取前两列(x 和 y 坐标),但仅适用于倒数第二列中包含“矩形”的行,使用逗号分隔符。
  2. 在每行末尾添加 1 或 0。第一行应该有 1,第 2-4 行应该有 0,第 5 行应该有 1,第 6-8 行应该有 0,依此类推。也就是说,每四行(从第一行开始)应该有一个 1,每隔一行应该有一个 0。

所以输出文件应该是这样的:

728257.89,5993759.24,1
728254.83,5993758.54,0
728251.82,5993762.4,0
728242.45,5993765.07,0

我已经尝试过这个问题的答案。例如

awk '
NR==1{
    for(i=1;i<=NF;i++)
        if($i!="z(ns)")
            cols[i]
}
{
    for(i=1;i<=NF;i++)
        if(i in cols)
            printf "%s ",$i
    printf "\n"
}' input.file > output.file

...删除第三列(然后对此进行修改以删除其他不需要的列)。但是,我剩下的只是一个空的输出文件。

我还尝试使用 grep 和 awk 一起破解解决方案:

touch output.txt
count=0
IFS=$'\n'
set -f #disable globbing
for i in $( grep "rectangle" $inputFile )
do
    Xcoord=$(awk 'BEGIN { FS=" " } { print $1 }' $i )
    printf "$Xcoord" >> output.txt
    echo ","
    Ycoord=$(awk 'BEGIN { FS=" " } { print $2 }' $i )
    printf "$Ycoord" >> output.txt
    printf ","
    count=$((count+1))
    if [[ count = "1" ]]
    then
        printf "$count\n" >> output.txt
    else
        printf "0\n" >> output.txt
    fi
done
set +f #re-enable globbing for future use of the terminal.

...这背后的想法是:-对于 $inputFile 中包含“矩形”的每一行

1. Append the first column (variable "Xcoord") to output.txt
2. Append a comma to output.txt
3. Append the second column (variable "Ycoord") to output.txt
4. Append another comma to output.txt
5. Append the 1 or 0 as per the if test based on the value of the variable "count", along with a new line.

这个想法失败了。它不是将数据保存到文件中,而是将文件的所有列打印到标准输出,第一列替换为文本“(没有这样的文件或目录)”:

来自我的 grep/awk 尝试的 STDOUT

...并且 output.txt 只是充满了零:

output.txt 内容

  1. 我怎样才能解决这个问题?
  2. 我需要做任何事情来使生成的 output.txt 文件为 Windows 格式吗?

提前致谢...

标签: bashdelimiter

解决方案


我认为 awk 能够在一行中满足您的所有需求:

 awk -F '[[:space:]][[:space:]]+' 'BEGIN{OFS = ","} {if ($8 == "rectangle") print $1, $2 }' a.txt | awk 'BEGIN{OFS = ","}{if((NR+3)%4) print $0,0;else print $0,1}'

您将条目之间的设置分隔符设置为“至少两个空格

-F '[[:space:]][[:space:]]+

将输出分隔符设置为逗号

'BEGIN{OFS = ","}

检查倒数第二列中的矩形条件

if ($8 == "rectangle")

并打印您想要的列作为输出

print $1, $2 

要在第三个输出列中添加 0,1 模式,您必须重新启动 awk 以获取结果文件的行号,而不是原始输入行。awk NR 变量包含从 1 开始的行号。

(NR+3)%4  

% 是模运算)对于第 1、5、9 行,结果为 0(=false),...所以您只需打印完整的行(变量 $0 ),然后在 if 情况下打印 0 和1 在其他情况下。

print $0,0;else print $0,1

希望这就是你想要的。


推荐阅读