Bash / C - 使用其他输出/文件中的值更正脚本输出中列中的无效值

时间:2016-08-25 14:03:52

标签: c bash awk sed

(重新访问并重新发布帖子。感谢您的澄清。)

我想请求您帮助解决我遇到的问题,对我来说这个行动方式并不是很清楚,除了一些基本的逻辑基础,我还在努力解决代码实现问题。

具体示例 - 输出,显示特定逻辑卷

//    $1_1                $1_2      $1_3 (for an ease I will call columns like this to distinguish it from the ones below
ALASKA_VOL00009873      offline    SB98MENO
FRANCE_ICSSI00964       online     FRANCE  //instead of SB91VMA3
JUNIPER_ROOT            suspended  S4MELIC15
NZELAND_VOL339643750    frozen     NZELAND //instead of S6B1B1AQ
DONKEYKONG_ISCSI002194  offline    SB99A95Z

如果第一列是逻辑卷的全名,第二列是状态(对我们来说不重要),第三列应该只包含服务器名称(在这种情况下,FRANCE和NZELAND不应该在那里,这些名称并且卷名的第一部分是“物理”上的虚拟服务器的名称,因此应该是我在其后键入的那些 - 修复这些需要对脚本添加新内容,这需要大量输出分析命令并以此形式格式化。

我想要的步骤将放在它之后 - 它将作为它的添加,当出现无效值时,它将修复第三列(SERVER NAME)中的可能问题。

对于这个问题,总会有一个文件包含来自其他脚本的输出,其中是与虚拟名称一起的服务器的正确名称。

此文件的内容将采用以下格式:

 //  $2_1         $2_2
    ALASKA       SB98MENO
    FRANCE       SB91VMA3
    JUNIPER      S4MELIC15
    NZELAND      S6B1B1AQ
    DONKEYKONG   SB99A95Z

第一列是虚拟服务器的名称,第二列是物理服务器的名称。

在这种情况下,它是新的一系列操作 - 我有一些从文件中选择内容的经验,这是在脚本之外,比较特定行和列中的特定值然后进行一些替换所以我想请你帮忙和建议。

我有这个想法,它应该如何运作 - 正如我所知(请忽略没有语法,这就像结构图)

它将作为for循环的补充

for (line counter, after each cycle it will move to the another line in the main output (first one), where)
do
 if (the value in the $1_3 matches the value in any line in the $2_1)
  then 
    "Value from the same line, but in the column $2_2" = "Actual scanned (by for) value in the particular line in the $1_3" // basically rewriting the incorrect value with the correct - there is the first problem I have - how to address all there different positions in the file, such as the value in the second column in the same row, where we found a match ????
  else
    continue (or break ???) //break the loop entirely
done

最后,想要的输出应该是:

ALASKA_VOL00009873      offline    SB98MENO
FRANCE_ICSSI00964       online     SB91VMA3
JUNIPER_ROOT            suspended  S4MELIC15
NZELAND_VOL339643750    frozen     S6B1B1AQ
DONKEYKONG_ISCSI002194  offline    SB99A95Z

为您提供一个正确的输出示例...以及我以前的输出

join -a1 -1 4 -2 1 <(echo "$VAR3") <(echo "$VAR2") | awk  '{print $2" "$3" "$4" - "$5}'

我收到了

     $2              $3     $4       $5       <--this is not in output, it is just for simple orientation, which column is which
APPLE_ISCSI01      offline aggrB2 - EELN1723
GRAPEFRUIT_ISCSI13 offline aggr1 -
GRAPEFRUIT_ISCSI04 offline aggr1 - XX643863
WOLFVILLE_ISCSI48  offline aggr1 - A7S5D1DCY0
WOLFVILLE_ISCSI49  offline aggr1 - A7S5D1DCY0
WOLFVILLE_ISCSI50  offline aggr1 - A7S5D1DCY0
WOLFVILLE_ISCSI51  offline aggr1 - A7S5D1DCY0

问题是第二行5美元的空白,实际上是

也没有标签,我刚刚添加了它们,因为它更清晰

没有awk,当然有这一列 - 这是第一列,在格式化时跳过

  $1
APPLE
XX643863
GRAPEFRUIT
WOLFVILLE
WOLFVILLE
WOLFVILLE
WOLFVILLE

基本上,现在我需要用这个XX643863(第二行)替换最终输出中的空格。 命令中的变量只是那些文本文件(也是排序的),但正如我所提到的,我想避免制作然后删除文件。

我试过你的awk - 遗憾的是没有成功。有没有可能用awk ...或sed?

1 个答案:

答案 0 :(得分:0)

您描述的进程是公共密钥上两个表之间的左连接。在SQL中,这可以通过查询来表示:

SELECT volumes.volume_name, volumes.volume_state, 
COALESCE(mapping.real_name, volumes.alias_name) 
FROM volumes LEFT JOIN mapping on volumes.alias_name = mapping.alias_name

实际上,对你来说可能的一个解决方案是在sqlite中加载它并执行该查询以获得结果,因为你可以获得csv / tsv(tabs)格式的数据:

create table volumes(volume_name varchar, status varchar, alias_name varchar);
create table mapping(alias_name varchar, real_name varchar);

.mode csv

.import volumes.csv volumes
.import mapping.csv mapping

.output result.csv

SELECT volumes.volume_name, volumes.status, 
COALESCE(mapping.real_name, volumes.alias_name) 
FROM volumes LEFT JOIN mapping on volumes.alias_name = mapping.alias_name;

然后可以使用命令cat script.sql|sqlite3将其作为脚本执行。

替代方案是:将join命令与sortawk一起使用,或者以bash或其他语言(awk或python)手动编写左连接。

以下是使用sortjoinawk的解决方案:

sort -k1 mapping > sorted_mapping
sort -k3 volumes > sorted_volumes

join -a1 -1 3 -2 1 sorted_volumes sorted_mapping

几乎可以提供你想要的东西:

FRANCE FRANCE_ICSSI00964 online SB91VMA3
NZELAND NZELAND_VOL339643750 frozen S6B1B1AQ
S4MELIC15 JUNIPER_ROOT suspended
SB98MENO ALASKA_VOL00009873 offline
SB99A95Z DONKEYKONG_ISCSI002194 offline

awk可用于正确格式化:

join -a1 -1 3 -2 1 sorted_volumes sorted_mapping|awk '{print $2, $3, NF==3 ? $1 : $NF}'

此解决方案称为sort-merge join

首先,我们使用sort命令对两个输入进行排序。然后我们使用join命令匹配具有相等键的行(匹配来自映射中第1列的卷的第3列)。 join将键作为第一列输出,因此我们必须使用awk手动重新排列列以匹配所需的输出格式。还有条件(三元运算符)通过检查列计数来检测卷和映射之间是否存在匹配。如果有匹配,我们从映射(最后一个)获取列,否则我们取密钥(第1列)。

更新

我不推荐它,因为它是狗 sloooo-oooooo-ow 并且基本上是重新发明自行车(手动执行join命令已经完成的事情),但是这里是nested loop左连接的bash版本

以前这里是bash中嵌套循环连接的天真实现,但它是如此 sl-oooooooo-ow 我决定用它的缓慢代替它取代它:

$ wc -l volumes2.txt             
100 volumes2.txt
$ wc -l mapping2.txt             
100 mapping2.txt
$ time ./nested_loops.sh > output                              

./nested_loops.sh > output  8.01s user 28.79s system 121% cpu 30.276 total

只是不要在纯粹的bash中进行嵌套循环连接。