【问题标题】:awk sed to replace empty spaces on the line based on the previous lineawk sed 根据上一行替换行上的空格
【发布时间】:2017-10-31 03:01:10
【问题描述】:

我有一个看起来像这样的文件,它是 windows 命令 icacls c:\path /t >output.txt

的结果
    C:\temp\2\ok Everyone:(I)(RX)
                 BUILTIN\Administrators:(I)(F)
                 NT AUTHORITY\SYSTEM:(I)(F)
                 BUILTIN\Users:(I)(RX)
                 NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\ok.txt Everyone:(I)(RX)
                     BUILTIN\Administrators:(I)(F)
                     NT AUTHORITY\SYSTEM:(I)(F)
                     BUILTIN\Users:(I)(RX)
                     NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\ok1.txt Everyone:(I)(RX)
                      BUILTIN\Administrators:(I)(F)
                      NT AUTHORITY\SYSTEM:(I)(F)
                      BUILTIN\Users:(I)(RX)
                      NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\ok2.txt Everyone:(I)(RX)
                      BUILTIN\Administrators:(I)(F)
                      NT AUTHORITY\SYSTEM:(I)(F)
                      BUILTIN\Users:(I)(RX)
                      NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\test1.ps1 Everyone:(I)(RX)
                        BUILTIN\Administrators:(I)(F)
                        NT AUTHORITY\SYSTEM:(I)(F)
                        BUILTIN\Users:(I)(RX)
                        NT AUTHORITY\Authenticated Users:(I)(M)

我需要用它前面的行填充不完全为空的空白空间。好消息是空格始终是基于前一行的相同数量的字符。

期望的输出

    C:\temp\2\ok Everyone:(I)(RX)
    C:\temp\2\ok BUILTIN\Administrators:(I)(F)
    C:\temp\2\ok NT AUTHORITY\SYSTEM:(I)(F)
    C:\temp\2\ok BUILTIN\Users:(I)(RX)
    C:\temp\2\ok NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\ok.txt Everyone:(I)(RX)
    C:\temp\2\ok.txt BUILTIN\Administrators:(I)(F)
    C:\temp\2\ok.txt NT AUTHORITY\SYSTEM:(I)(F)
    C:\temp\2\ok.txt BUILTIN\Users:(I)(RX)
    C:\temp\2\ok.txt NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\ok1.txt Everyone:(I)(RX)
    C:\temp\2\ok1.txt BUILTIN\Administrators:(I)(F)
    C:\temp\2\ok1.txt NT AUTHORITY\SYSTEM:(I)(F)
    C:\temp\2\ok1.txt BUILTIN\Users:(I)(RX)
    C:\temp\2\ok1.txt NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\ok2.txt Everyone:(I)(RX)
    C:\temp\2\ok2.txt BUILTIN\Administrators:(I)(F)
    C:\temp\2\ok2.txt NT AUTHORITY\SYSTEM:(I)(F)
    C:\temp\2\ok2.txt BUILTIN\Users:(I)(RX)
    C:\temp\2\ok2.txt NT AUTHORITY\Authenticated Users:(I)(M)

    C:\temp\2\test1.ps1 Everyone:(I)(RX)
    C:\temp\2\test1.ps1 BUILTIN\Administrators:(I)(F)
    C:\temp\2\test1.ps1 NT AUTHORITY\SYSTEM:(I)(F)
    C:\temp\2\test1.ps1 BUILTIN\Users:(I)(RX)
    C:\temp\2\test1.ps1 NT AUTHORITY\Authenticated Users:(I)(M)

我尝试过这样的事情: 为了获得两个文件并将它们粘贴在一起,但问题是意外的空格总是搞乱顺序(我使用的是 Windows awk 和 sed,这就是我使用双引号的原因)

    awk  "{line=$2} {print NF?line:\"\"}" OUTPUT
    awk  "{line=$1} {print NF?line:\"\"}" OUTPUT
    awk -F":" "{line=$2} {print NF?line:\"\"}" OUTPUT
    awk -F":" "{line=$1} {print NF?line:\"\"}" OUTPUT

我会很感激任何其他想法

【问题讨论】:

  • 文件中的“第一”行实际上是左对齐的,还是在它们之前有空格?
  • 那些空格是误加的,其实是没有空格的
  • @Eduardo:你的起跑线总是有Everyone:(I)(RX) 吗?
  • @batMan 恐怕不会,它会改变。第一部分也会改变,它会有像“c:\New Folder”这样的空格
  • @Eduardo:下一个问题,第一行中将替换Everyone:(I)(RX) 的字段可以有空格吗?

标签: awk sed


【解决方案1】:

awk 来救援!

awk '/^$/{k=""} !k{k=$1;$1=""} {sub(/^ +/,k FS)}1'


C:\temp\2\ok Everyone:(I)(RX)
C:\temp\2\ok BUILTIN\Administrators:(I)(F)
C:\temp\2\ok NT AUTHORITY\SYSTEM:(I)(F)
C:\temp\2\ok BUILTIN\Users:(I)(RX)
C:\temp\2\ok NT AUTHORITY\Authenticated Users:(I)(M)

C:\temp\2\ok.txt Everyone:(I)(RX)
C:\temp\2\ok.txt BUILTIN\Administrators:(I)(F)
C:\temp\2\ok.txt NT AUTHORITY\SYSTEM:(I)(F)
C:\temp\2\ok.txt BUILTIN\Users:(I)(RX)
C:\temp\2\ok.txt NT AUTHORITY\Authenticated Users:(I)(M)

C:\temp\2\ok1.txt Everyone:(I)(RX)
C:\temp\2\ok1.txt BUILTIN\Administrators:(I)(F)
C:\temp\2\ok1.txt NT AUTHORITY\SYSTEM:(I)(F)
C:\temp\2\ok1.txt BUILTIN\Users:(I)(RX)
C:\temp\2\ok1.txt NT AUTHORITY\Authenticated Users:(I)(M)

C:\temp\2\ok2.txt Everyone:(I)(RX)
C:\temp\2\ok2.txt BUILTIN\Administrators:(I)(F)
C:\temp\2\ok2.txt NT AUTHORITY\SYSTEM:(I)(F)
C:\temp\2\ok2.txt BUILTIN\Users:(I)(RX)
C:\temp\2\ok2.txt NT AUTHORITY\Authenticated Users:(I)(M)

C:\temp\2\test1.ps1 Everyone:(I)(RX)
C:\temp\2\test1.ps1 BUILTIN\Administrators:(I)(F)
C:\temp\2\test1.ps1 NT AUTHORITY\SYSTEM:(I)(F)
C:\temp\2\test1.ps1 BUILTIN\Users:(I)(RX)
C:\temp\2\test1.ps1 NT AUTHORITY\Authenticated Users:(I)(M)

您可能需要适应 windows 格式。

【讨论】:

    【解决方案2】:

    我讨厌自己,所以我决定挑战自己,只使用 sed 来解决它。事实证明这是完全可行的:

    $ cat /tmp/test.sed
    h
    :first
    n
    s/^\s*$/&/
    t last
    H
    s/^//
    t first
    :last
    x
    :loop
    s/^(.*)(Every.*)(\1[^\n]*)$/\1\2\3/
    t break
    s/(.*)(Every[^\n]*)((\n\1[^\n]*)*)\n\s*/\1\2\3\n\1/
    t loop
    :break
    p
    g
    p
    

    而且肯定达到了效果:

    $ sed -n -r -f /tmp/test.sed /tmp/try
        C:\temp\2\ok Everyone:(I)(RX)
        C:\temp\2\ok BUILTIN\Administrators:(I)(F)
        C:\temp\2\ok NT AUTHORITY\SYSTEM:(I)(F)
        C:\temp\2\ok BUILTIN\Users:(I)(RX)
        C:\temp\2\ok NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\ok.txt Everyone:(I)(RX)
        C:\temp\2\ok.txt BUILTIN\Administrators:(I)(F)
        C:\temp\2\ok.txt NT AUTHORITY\SYSTEM:(I)(F)
        C:\temp\2\ok.txt BUILTIN\Users:(I)(RX)
        C:\temp\2\ok.txt NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\ok1.txt Everyone:(I)(RX)
        C:\temp\2\ok1.txt BUILTIN\Administrators:(I)(F)
        C:\temp\2\ok1.txt NT AUTHORITY\SYSTEM:(I)(F)
        C:\temp\2\ok1.txt BUILTIN\Users:(I)(RX)
        C:\temp\2\ok1.txt NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\ok2.txt Everyone:(I)(RX)
        C:\temp\2\ok2.txt BUILTIN\Administrators:(I)(F)
        C:\temp\2\ok2.txt NT AUTHORITY\SYSTEM:(I)(F)
        C:\temp\2\ok2.txt BUILTIN\Users:(I)(RX)
        C:\temp\2\ok2.txt NT AUTHORITY\Authenticated Users:(I)(M)
    

    我的神秘解决方案解释如下:

    h  # overwrite hold buffer with current line
    :first  # set a label
    n  # overwrite current line(pattern buffer) with next line
    s/^\s*$/&/  # are we currently in blank line?
    t last  # if so, we jump to :last, continue otherwise
    H  # we append current line to hold buffer
    s/^// # always true
    t first  # so we will be going back to :first
    :last
    x  # so now we have all lines related to the single file. then we xchange the hold buffer to pattern buffer
    :loop  # we need to loop to loop through all lines
    s/^(.*)(Every.*)(\1[^\n]*)$/\1\2\3/  # have we substituted all lines yet?
    t break  # if so, we break the loop, continue otherwise
    s/(.*)(Every[^\n]*)((\n\1[^\n]*)*)\n\s*/\1\2\3\n\1/  # then we make sure each iteration will replace leading blanks with file path
    t loop  # go back to the beginning of the loop
    :break
    p  # we print all we have now substituted
    g  # get back the blank line
    p  # print the blank line
    

    此代码自动适应任意行,例如这种形式的属性,只要它们用空行分隔即可。这还不算太糟糕,不是吗?如果你愿意,请帮助我改进它。

    【讨论】:

    • 非常感谢,它适用于当前目录,但恐怕我在这个文件中有很多文件夹不遵循相同的 3 个斜线模式。是否可以将相同的字符从上一行复制到带有空格的行,直到出现第二行的文本?例如:C:\temp\New 文件夹 BUILTIN\Administrators:(I)(F) BUILTIN\Administrators:(I)(OI)(CI)(IO)(F) NT AUTHORITY\SYSTEM:(I)(F)
    • @Eduardo 正如我所说,只要每个文件用空行分隔,这段代码就会适应这种格式。它没有假设路径包含 3 个斜杠。
    • 这很奇怪,由于某种原因,它适用于包含此问题文本的文件,但如果有像 C:\new 文件夹或 C:\temp\new 文件夹这样的文件夹,它会留空空格。
    • @Eduardo 你的第一行是什么?可能是every 部分不正确
    • 例如第一行说:c:\Program Files\7-Zip NT SERVICE\TrustedInstaller:(I)(F)
    【解决方案3】:

    关注awk 应该对您有所帮助。

    awk '/^C:\\/{val=$1;print;next} NF{sub(/^ +/,"");print val,$0;next} 1'  Input_file
    

    在这里也添加非单行形式的解决方案并附上解释。

    awk '
    /^C:\\/{         ##Checking condition here if any line starts from C:\\, point to be noted here I am escaping \ for removing its special meaning.
     val=$1;         ##If any line starts from C:\\ then it will be come in this block, assigning variable named val to first field here.
     print;          ##Printing that specific line now.
     next            ##next is to skip all further statements from this line onwards and move the cursor to next line with starting of the statements.
    }
    NF{              ##Checking condition here if any line is NOT NULL so NF means number of fields and checking of number of fields variable is NOT NULL, if yes then do following.
     sub(/^ +/,"");  ##Substituting initial space with NULL in current line.
     print val,$0;   ##Printing variable named val and current line now.
    next             ##Use next statement to skip further statements.
    }
    1                ##Mentioning 1 here to make the condition TRUE, so awk works on method of regexp and action, here I am making condition/regexp TRUE by mentioning 1 and not mentioning any action here so by default print of current line will happen.
    ' Input_file     ##Mentioning Input_file name here.
    

    【讨论】:

    • 非常感谢,它完全按照要求工作。我只是将它改编为 UNC 路径。
    • @Eduardo,很高兴它对你有所帮助,继续学习,继续分享,干杯!!
    【解决方案4】:

    甚至,如下所示,在预期输出中以空格开头。

    awk '{/C:/? s=$1 : NF ? $0 = s OFS $0 : ""; $1= "  "$1 }1' infile
    

    测试结果:

    $ cat infile
        C:\temp\2\ok Everyone:(I)(RX)
                     BUILTIN\Administrators:(I)(F)
                     NT AUTHORITY\SYSTEM:(I)(F)
                     BUILTIN\Users:(I)(RX)
                     NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\ok.txt Everyone:(I)(RX)
                         BUILTIN\Administrators:(I)(F)
                         NT AUTHORITY\SYSTEM:(I)(F)
                         BUILTIN\Users:(I)(RX)
                         NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\ok1.txt Everyone:(I)(RX)
                          BUILTIN\Administrators:(I)(F)
                          NT AUTHORITY\SYSTEM:(I)(F)
                          BUILTIN\Users:(I)(RX)
                          NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\ok2.txt Everyone:(I)(RX)
                          BUILTIN\Administrators:(I)(F)
                          NT AUTHORITY\SYSTEM:(I)(F)
                          BUILTIN\Users:(I)(RX)
                          NT AUTHORITY\Authenticated Users:(I)(M)
    
        C:\temp\2\test1.ps1 Everyone:(I)(RX)
                            BUILTIN\Administrators:(I)(F)
                            NT AUTHORITY\SYSTEM:(I)(F)
                            BUILTIN\Users:(I)(RX)
                            NT AUTHORITY\Authenticated Users:(I)(M)
    

    输出:

    $ awk '{/C:/? s=$1 : NF ? $0 = s OFS $0 : ""; $1= "  "$1 }1' infile
      C:\temp\2\ok Everyone:(I)(RX)
      C:\temp\2\ok BUILTIN\Administrators:(I)(F)
      C:\temp\2\ok NT AUTHORITY\SYSTEM:(I)(F)
      C:\temp\2\ok BUILTIN\Users:(I)(RX)
      C:\temp\2\ok NT AUTHORITY\Authenticated Users:(I)(M)
    
      C:\temp\2\ok.txt Everyone:(I)(RX)
      C:\temp\2\ok.txt BUILTIN\Administrators:(I)(F)
      C:\temp\2\ok.txt NT AUTHORITY\SYSTEM:(I)(F)
      C:\temp\2\ok.txt BUILTIN\Users:(I)(RX)
      C:\temp\2\ok.txt NT AUTHORITY\Authenticated Users:(I)(M)
    
      C:\temp\2\ok1.txt Everyone:(I)(RX)
      C:\temp\2\ok1.txt BUILTIN\Administrators:(I)(F)
      C:\temp\2\ok1.txt NT AUTHORITY\SYSTEM:(I)(F)
      C:\temp\2\ok1.txt BUILTIN\Users:(I)(RX)
      C:\temp\2\ok1.txt NT AUTHORITY\Authenticated Users:(I)(M)
    
      C:\temp\2\ok2.txt Everyone:(I)(RX)
      C:\temp\2\ok2.txt BUILTIN\Administrators:(I)(F)
      C:\temp\2\ok2.txt NT AUTHORITY\SYSTEM:(I)(F)
      C:\temp\2\ok2.txt BUILTIN\Users:(I)(RX)
      C:\temp\2\ok2.txt NT AUTHORITY\Authenticated Users:(I)(M)
    
      C:\temp\2\test1.ps1 Everyone:(I)(RX)
      C:\temp\2\test1.ps1 BUILTIN\Administrators:(I)(F)
      C:\temp\2\test1.ps1 NT AUTHORITY\SYSTEM:(I)(F)
      C:\temp\2\test1.ps1 BUILTIN\Users:(I)(RX)
      C:\temp\2\test1.ps1 NT AUTHORITY\Authenticated Users:(I)(M)
    

    【讨论】:

    • 谢谢,如果文件/文件夹有空格,例如 C:\New Folder\subfolder\New text file.txt,是否也可以让它工作?跨度>
    【解决方案5】:

    让我们以其他方式尝试 awk

    awk '{
    if(/^C:\\temp/) {x=$1;print}
    else if(/[:alpha]/) {gsub(/^[ \t]+/," "); print x $0}
    else print;     
    }' ipfile
    

    【讨论】:

      猜你喜欢
      • 2016-10-29
      • 1970-01-01
      • 2018-05-24
      • 2011-01-23
      • 2020-10-29
      • 2020-11-03
      • 2019-09-04
      • 1970-01-01
      • 2015-05-30
      相关资源
      最近更新 更多