![如何格式化文件从第 30 个制表符或第 88 个空格开始的最后 3 列](https://linux22.com/image/138007/%E5%A6%82%E4%BD%95%E6%A0%BC%E5%BC%8F%E5%8C%96%E6%96%87%E4%BB%B6%E4%BB%8E%E7%AC%AC%2030%20%E4%B8%AA%E5%88%B6%E8%A1%A8%E7%AC%A6%E6%88%96%E7%AC%AC%2088%20%E4%B8%AA%E7%A9%BA%E6%A0%BC%E5%BC%80%E5%A7%8B%E7%9A%84%E6%9C%80%E5%90%8E%203%20%E5%88%97.png)
Ubuntu 16.04 GNU bash,版本 4.4.0
我想格式化这个包含 1,264,524 行邮政编码的文本文件。
#!/bin/bash
wget http://download.geonames.org/export/zip/allCountries.zip
unzip allCountries.zip
mv -f allCountries.txt .allCountries.txt
rm -f allCountries.zip
这是文件中未格式化的部分。
AD AD100 Canillo 42.5833 1.6667 6
AD AD200 Encamp 42.5333 1.6333 6
AD AD300 Ordino 42.6 1.55 6
AD AD400 La Massana 42.5667 1.4833 6
AD AD500 Andorra la Vella 42.5 1.5 6
AD AD600 Sant Julià de Lòria 42.4667 1.5 6
AD AD700 Escaldes-Engordany 42.5 1.5667 6
AR 3636 POZO CERCADO (EL CHORRO (F), DPTO. RIVADAVIA (S)) Salta A -23.4933 -61.9267 3
AR 4123 LAS SALADAS Salta A -25.7833 -64.5 4
AR 4126 BARADERO Salta A -26.0833 -65.263 3
AR 4126 EL CUIBAL Salta A -26.0833 -65.263 3
AR 4126 LA ASUNCION Salta A -26.0833 -65.263 3
AR 4126 MIRAFLORES (TALA, DPTO. CANDELARIA) Salta A -26.0833 -65.263 3
AR 4141 TOLOMBON Salta A -26.2 -65.9167 4
AR 4141 QUISCA GRANDE Salta A -26.4367 -65.97 3
AR 4141 LA CIENEGUITA Salta A -26.4367 -65.97 3
AR 4141 MACHO RASTROJO Salta A -26.4367 -65.97 3
AR 4190 ROSARIO DE LA FRONTERA Salta A -25.8 -64.9667 4
AR 4190 OVANDO Salta A -25.8 -65.1 4
AR 4190 SAN ESTEBAN Salta A -25.8 -65.0333 3
AR 4190 LA BANDA (R. DE LA FRONTERA, DPTO. ROSARIO DE LA FRONTERA) Salta A -25.8 -65.0333 3
AR 4190 LA MATILDE Salta A -25.8 -65.0333 3
AR 4190 LAS PIEDRITAS Salta A -25.8 -65.0333 3
AR 4190 LOS POCITOS Salta A -25.8 -65.0333 3
AR 4190 OJO DE AGUA (ROSARIO DE LA FRONTERA, DPTO. R.DE LA FRONTERA) Salta A -25.8 -65.0333 3
AR 4190 POTRERILLO (R. DE LA FRONTERA, DPTO. ROSARIO DE LA FRONTERA) Salta A -25.8 -65.0333 3
这应该是最终的结果:
AD AD100 Canillo 42.5833 1.6667 6
AD AD200 Encamp 42.5333 1.6333 6
AD AD300 Ordino 42.6 1.56 6
AD AD400 La Massana 42.5667 1.4833 6
AD AD500 Andorra la Vella 42.5 1.6 6
AD AD600 Sant Julià de Lòria 42.4667 1.5 6
AD AD700 Escaldes-Engordany 42.5 1.5667 6
AR 3636 POZO CERCADO (EL CHORRO (F), DPTO. RIVADAVIA (S)) Salta A -23.4933 -61.9267 3
AR 4123 LAS SALADAS Salta A -25.7833 -64.5 4
AR 4126 BARADERO Salta A -26.0833 -65.263 3
AR 4126 EL CUIBAL Salta A -26.0833 -65.263 3
AR 4126 LA ASUNCION Salta A -26.0833 -65.263 3
AR 4126 MIRAFLORES (TALA, DPTO. CANDELARIA) Salta A -26.0833 -65.263 3
AR 4141 TOLOMBON Salta A -26.2 -65.9167 4
AR 4190 OJO DE AGUA (ROSARIO DE LA FRONTERA, DPTO. R.DE LA FRONTERA) Salta A -25.8 -65.0333 3
AR 4190 POTRERILLO (R. DE LA FRONTERA, DPTO. ROSARIO DE LA FRONTERA) Salta A -25.8 -65.0333 3
因此,从第 3 列到最后一列的左侧应从第 30 个制表符或 88 个空格开始。最后 3 列的第一个字符相距 12 个空格。
每行都有数据,所以我尝试将最后 3 列剪切到另一个文件中。然后我尝试从原始文件中删除所有空格,然后将其格式化为列。第三列给我带来了麻烦,因为如果这样做
awk 'BEGIN{ OFS="\t"}{ print $1, $2, NR }' .allCountries.txt
AT 4873 Pehigen 34069
AT 4873 Hofberg 34070
AT 4873 Wiederhals 34071
AT 4873 Oberedt 34072
AT 4873 Oberegg 34073
AT 4873 Raitenberg 34074
AT 4873 Redltal 34075
AT 4873 Friedhalbing 34076
AT 4873 Unterhaselbach 34077
AT 4873 Redltal 34078
AT 4873 Erkaburgen 34079
AT 4873 Mayrhof 34080
AT 4873 Erdpries 34081
AT 4873 Grünbergsiedlung 34082
AT 4873 Brunnhölzl 34083
AT 4873 Seibrigen 34084
AT 4873 Kinast 34085
AT 4873 Stöckert 34086
AT 4873 Frankenburg 34087
AT 4873 Fischeredt 34088
AT 4873 Marigen 34089
AT 4873 Oberhaselbach 34090
AT 4873 Ottokönigen 34091
AT 4873 Fischigen 34092
AT 4873 Endriegl 34093
任何帮助都会很大。
答案1
这似乎可以做到。作为一个简单的单行awk
,它对于 1.2m 行的文件应该运行得相当快。通过根据您的示例创建一个 130 万行的虚拟文件,我看到它在具有 4GB 内存和 GNU Awk 4.0.2 的基本 CentOS 7 VM 上在 24 秒内完成。
为了从 StackExchange 获得一些准确的响应,您可能需要将示例输入与示例输出一起发布在 Pastebin 上。
$ awk '{printf "%s %-6s%-81s%-12s%-12s%s\n",$1,$2,gensub(/[0-9.-]* +[0-9.-]* +[0-9]$/,"","g",substr($0,10)),$(NF-2),$(NF-1),$NF}' inp | head
AD AD100 Canillo 42.5833 1.6667 6
AD AD200 Encamp 42.5333 1.6333 6
AD AD300 Ordino 42.6 1.55 6
AD AD400 La Massana 42.5667 1.4833 6
AD AD500 Andorra la Vella 42.5 1.5 6
AD AD600 Sant Julià de Lòria 42.4667 1.5 6
AD AD700 Escaldes-Engordany 42.5 1.5667 6
AR 3636 POZO CERCADO (EL CHORRO (F), DPTO. RIVADAVIA (S)) Salta A -23.4933 -61.9267 3
AR 4123 LAS SALADAS Salta A -25.7833 -64.5 4
AR 4126 BARADERO Salta A -26.0833 -65.263 3
$
答案2
我能够通过以下脚本完成我认为您想要的任务,尽管我不确定它在 100 万行以上的情况下效果如何。
#!/usr/local/bin/bash
tmp_dir="$(mktemp -d -t 'text.XXXXX' || mktemp -d 2>/dev/null)"
input=./input
output=./output
tmp_input1=${tmp_dir}/temp_input1.txt
tmp_input2=${tmp_dir}/temp_input2.txt
col1="${tmp_dir}/col1.txt"
col2="${tmp_dir}/col2.txt"
col3="${tmp_dir}/col3.txt"
col4="${tmp_dir}/col4.txt"
col5="${tmp_dir}/col5.txt"
col6="${tmp_dir}/col6.txt"
tr -s ' ' <"$input" > "$tmp_input1"
awk '{print $1}' "$tmp_input1" > "$col1"
awk '!($1="")' "$tmp_input1" > "$tmp_input2"
awk '{print $1}' "$tmp_input2" > "$col2"
awk '!($1="")' "$tmp_input2" > "$tmp_input1"
awk '{print $NF}' "$tmp_input1" > "$col6"
awk '!($NF="")' "$tmp_input1" > "$tmp_input2"
awk '{print $NF}' "$tmp_input2" > "$col5"
awk '!($NF="")' "$tmp_input2" > "$tmp_input1"
awk '{print $NF}' "$tmp_input1" > "$col4"
awk '!($NF="")' "$tmp_input1" > "$tmp_input2"
cat "$tmp_input2" > "$col3"
paste -d'\t' "$col1" "$col2" "$col3" "$col4" "$col5" "$col6" | column -s$'\t' -t > "$output"
rm -r "$tmp_dir"
这会创建一堆 tmp 文件(每列一个,两个用于修改原始文件),并通过原始输入进行处理,一次删除一列,直到只剩下第 3 列。然后,它将所有 tmp 文件以制表符分隔粘贴在一起并column
根据需要格式化输出。
根据您给定的输入:
$ ./script.sh
$ cat output
AD AD100 Canillo 42.5833 1.6667 6
AD AD200 Encamp 42.5333 1.6333 6
AD AD300 Ordino 42.6 1.55 6
AD AD400 La Massana 42.5667 1.4833 6
AD AD500 Andorra la Vella 42.5 1.5 6
AD AD600 Sant Julià de Lòria 42.4667 1.5 6
AD AD700 Escaldes-Engordany 42.5 1.5667 6
AR 3636 POZO CERCADO (EL CHORRO (F), DPTO. RIVADAVIA (S)) Salta A -23.4933 -61.9267 3
AR 4123 LAS SALADAS Salta A -25.7833 -64.5 4
AR 4126 BARADERO Salta A -26.0833 -65.263 3
AR 4126 EL CUIBAL Salta A -26.0833 -65.263 3
AR 4126 LA ASUNCION Salta A -26.0833 -65.263 3
AR 4126 MIRAFLORES (TALA, DPTO. CANDELARIA) Salta A -26.0833 -65.263 3
AR 4141 TOLOMBON Salta A -26.2 -65.9167 4
AR 4141 QUISCA GRANDE Salta A -26.4367 -65.97 3
AR 4141 LA CIENEGUITA Salta A -26.4367 -65.97 3
AR 4141 MACHO RASTROJO Salta A -26.4367 -65.97 3
AR 4190 ROSARIO DE LA FRONTERA Salta A -25.8 -64.9667 4
AR 4190 OVANDO Salta A -25.8 -65.1 4
AR 4190 SAN ESTEBAN Salta A -25.8 -65.0333 3
AR 4190 LA BANDA (R. DE LA FRONTERA, DPTO. ROSARIO DE LA FRONTERA) Salta A -25.8 -65.0333 3
AR 4190 LA MATILDE Salta A -25.8 -65.0333 3
AR 4190 LAS PIEDRITAS Salta A -25.8 -65.0333 3
AR 4190 LOS POCITOS Salta A -25.8 -65.0333 3
AR 4190 OJO DE AGUA (ROSARIO DE LA FRONTERA, DPTO. R.DE LA FRONTERA) Salta A -25.8 -65.0333 3
AR 4190 POTRERILLO (R. DE LA FRONTERA, DPTO. ROSARIO DE LA FRONTERA) Salta A -25.8 -65.0333 3