【问题标题】:awk output with spaces in first columnawk 输出,第一列有空格
【发布时间】:2020-10-23 16:09:51
【问题描述】:

我尝试使用 awk 拆分列来打印一个句子,但第一列有空格。

我的初学者代码示例:

$ awk '/Linux/ { print "The filename","\""$1"\"","is located in",$2 }' test.txt
The filename "The" is located in test
The filename "Some" is located in file
The filename "File" is located in name
The filename "Something_here" is located in /ABC
The filename "Another_test" is located in /DEFG
The filename "Label" is located in test

来自文件:test.txt

Filename                               Folder         Type
-------------------------------------- -------------- ------
The test file                          /test/folder   Linux
Some file                              /              Linux
File name                              /Temp          Linux
Something_here                         /ABC           Linux
Another_test                           /DEFG          Linux
Label test                             /HIJK          Linux 

我想要达到的目标:(包括引号)

The filename "Default file" is located in / 
The filename "The test file" is located in /test/folder

问题是当我使用“空格”或“/”作为分隔符时,打印时无法获取整行

【问题讨论】:

  • 请提供您正在使用的脚本或命令。另外,你现在得到的输出。
  • @KimochiIku 你可以编辑你的帖子。请将您的评论内容移至您的帖子中。

标签: awk


【解决方案1】:

如果您有 GNU AWK,这应该可以解决问题:

awk 'match($0, /([^\/]+)([^ ]+) *Linux/, arr) { sub(/ +$/, "", arr[1]); printf("The filename \"%s\" is located in %s\n", arr[1], arr[2]) }' test.txt

解释:


# match and store groups in 'arr'
#  - arr[1]: everything up until the first slash (including a lot of whitespace)
#  - arr[2]: first slash until space
#  - rest: also ensure there's 'Linux' after that
match($0, /([^\/]+)([^ ]+) *Linux/, arr) {

  # trim whitespace from the right hand side of the filename
  sub(/ +$/, "", arr[1]);

  # print
  printf("The filename \"%s\" is located in %s\n", arr[1], arr[2])
}

请注意,在其他风格的 AWK 中还有一个功能较弱的 match 版本,使用这些也可以实现相同的目标,但您必须编写更多代码。

【讨论】:

  • 这行得通!这些 arr[] 称为子数组吗?以前从未使用过命令匹配,您可以使用 == 还是它们不同?
  • arr 是一个包含多个值的数组。例如。在位置 1 (arr[1]) 存储文件名。如果要比较内容,可以执行arr[1] == "mystring" 之类的操作。如果您在终端中,您也可以输入man awk,它会为您提供大量有关此的信息:) 另外,由于这对您有用,您能接受答案吗?谢谢
【解决方案2】:

GNU awk 具有正则表达式字段分隔符,因此只需要多个空格分隔您的列。

awk '/Linux/ { print "The file \""$1"\" is in "$2"." }' FS="   *" test.txt

它还提供固定宽度的字段,比如info gawk fieldwidths,您可以使用虚线的长度来即时设置这些字段。

【讨论】:

  • 不错,但它不会自动适应文件名中的空白。如果你有“测试文件”作为文件名,这个特定的命令行将不起作用。
  • 无论如何,数据格式都不足以处理这个问题,文件名中的尾随空格是无法检测到的。前导空白的可能性是我提到字段宽度的原因。
  • 我说的是名称中的空格,而不是前导和尾随的...但是像这样的名称除了可能是一些在其名称中嵌入其标题的声音文件外,非常奇怪...
【解决方案3】:

我建议sed 使用基于正则表达式和反向引用的替换加上grep 命令来消除源文件的标题行:

$ cat test.txt | grep -E 'Linux[ ]*$' | sed -E 's%(.+)([^ ])([ ]+)(/.+)[ ]+Linux[ ]*$%The filename "\1\2" is located in \4%'
The filename "The test file" is located in /test/folder  
The filename "Some file" is located in /             
The filename "File name" is located in /Temp         
The filename "Something_here" is located in /ABC          
The filename "Another_test" is located in /DEFG         
The filename "Label test" is located in /HIJK

正则表达式 (regex) 的一个很好的参考在 Linux manuals

评论中要求的详细描述:

  • 带有 -E 选项的 grep 接受扩展的 regex(上面的参考文档)。在这里,它用于过滤包含“Linux”字样的行,如果每行末尾有空格,则后跟一些空格
  • grep 的输出进入 sed 的输入
  • sed 通过 -E 选项(如 grep)来接受扩展的 regexs 命令替换匹配 regex 的字符(第一部分在 % chars = "(.+)([^ ])([ ]+)(/.+) [ ]+Linux[ ]*$") 其他人(% chars 之间的第二部分 = "文件名 "\1\2" 位于 \4")。
  • 第二部分使用反向引用:'\' 后跟一个非零十进制数字 n正则表达式的第 n 个带括号的子表达式替换。在这里,\1 被匹配第一个“(.+)”的字符串替换,这是这里的文件名,\2 被下面的“([^ ])”替换,这是文件名的最后一个字符(技巧到禁止名称中的以下空格)...

这不是一个严格的解释,但至少它提供了一些更进一步的输入。

另一种解决方案是在 sed 命令行上传递多个操作。因此,您可以添加一个查询来删除前 2 个标题行,以使用 catgrep 抑制管道。这里的“1,2d”,意思是“删除第 1 行和第 2 行”:

$ sed -E '1,2d;s%(.+)([^ ])([ ]+)(/.+)[ ]+Linux[ ]*$%The filename "\1\2" is located in \4%' test.txt
The filename "The  test file" is located in /test/folder  
The filename "Some file" is located in /             
The filename "File name" is located in /Temp         
The filename "Something_here" is located in /ABC          
The filename "Another_test" is located in /DEFG         
The filename "Label test" is located in /HIJK

注意:根据manual-E 选项切换为使用扩展正则表达式。 GNU sed 多年来一直支持它,现在已包含在 POSIX 中。 在旧系统上,如果不支持 -E,则可以使用 -r

$ sed -r '1,2d;s%(.+)([^ ])([ ]+)(/.+)[ ]+Linux[ ]*$%The filename "\1\2" is located in \4%' test.txt
The filename "The  test file" is located in /test/folder  
The filename "Some file" is located in /             
The filename "File name" is located in /Temp         
The filename "Something_here" is located in /ABC          
The filename "Another_test" is located in /DEFG         
The filename "Label test" is located in /HIJK

【讨论】:

  • 你能分解你的命令,了解它是什么/如何工作的吗? awk with while read 也在这项工作中吗?
  • 我更新了解释sed命令行的答案。
  • sed: 无效选项 -- 'E' 用法: sed [OPTION]... {script-only-if-no-other-script} [input-file]... sed --版本 GNU sed 版本 4.1.5
  • 我的 sed 命令更新:sed (GNU sed) 4.7。是否支持“-r”选项?它是 -E 的同义词。
  • 是的,用 -r 尝试了 sed,谢谢!但希望学习如何在 awk 选项中执行此操作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多