【问题标题】:Bash: Remove beginning part of string that's random with space as the delimiterBash:删除以空格为分隔符的随机字符串的开头部分
【发布时间】:2014-11-11 04:20:42
【问题描述】:

我正在使用这个命令:

find -type f -printf "%s %p\n" | sort -nr | head -n 4

我得到这样的输出:

374266 lecture04/address-translation.png
2629 lecture04/lecture04-display.txt
1880 lecture04/lecture04-class16.txt
1828 lecture04/quiz-participation-04.zip

如何使用 grep、sed 或 awk 从字符串开头删除文件大小和空间?虽然我需要按大小顺序列出文件路径,从大到小,但对于我的脚本,我不需要在此命令之后知道它们的确切大小。我一直在阅读手册页和谷歌搜索,但我只是不知道如何做到这一点。我希望它看起来像这样:

lecture04/address-translation.png
lecture04/lecture04-display.txt
lecture04/lecture04-class16.txt
lecture04/quiz-participation-04.zip

一旦输入格式像这样,我想将每个路径放在它自己的单元格中的一个数组中,用于我的脚本的其余部分。

我觉得这是一个简单的问题,当我在 Stack Exchange 上发现类似问题时,他们只是有一个针对我难以理解的问题量身定制的命令。如果你能回答这个问题,你介意解释一下这个命令吗?

【问题讨论】:

    标签: bash awk sed grep


    【解决方案1】:

    cut 的工作就是被发明出来的:

    cut -d' ' -f2-
    
    man cut
    

    使用命令的结果填充名为arr 的shell 数组将是

    arr=( $(find ... | cut -d' ' -f2-) )
    

    如果你有带空格的文件名:

    $ cat file
    374266 /path to /the file
    12345 /path   to another/file
    
    $ cat file | cut -d' ' -f2-
    /path to /the file
    /path   to another/file
    
    $ IFS=$'\n' arr=( $(cat file | cut -d' ' -f2-) )
    
    $ echo "${arr[0]}"
    /path to /the file
    
    $ echo "${arr[1]}"
    /path   to another/file
    

    显然我使用cat file 代替您的find 命令,而不是建议您剪切文件。对于包含换行符的文件名,上述操作将失败。如果有,请查看 find -print0xargs -0 作为解决方案的起点。

    您应该按照以下 cmets 中 @gnourf_gnourf 的建议使用 mapfile:

    $ cat file
    374266 .*
    12345 /path   to another/file
    
    $ IFS=$'\n' arr=( $(cat file | cut -d' ' -f2-) )
    
    $ echo "${arr[0]}"
    .
    
    $ echo "${arr[1]}"
    ..
    
    $ mapfile -t arr < <(cat file | cut -d' ' -f2-)
    
    $ echo "${arr[0]}"
    .*
    
    $ echo "${arr[1]}"
    /path   to another/file
    

    man mapfileman bash 获取 mapfile 命令行的语法或询问 @gnourf_gnourf!

    【讨论】:

    • 如果文件路径中有空格会失败吗?另外我该如何进行管道,如果这是正确的术语,输出到数组中?
    • 当它进入数组时,带有空格的文件路径被分解。似乎空格是分隔符,所以 7952096 ./old/Sublime Text 2/sublime_text 进入数组为:arr[0] = ./old/Sublime 然后 arr[1] = Textand arr[2] = 2/sublime_text
    • 是的,没错。当您提出问题以发布真正具有代表性的数据和预期输出时,这一点很重要,这样我们才能提供合适的答案,因为如果您不提供合适的测试用例,我们不会总是想到潜在的问题。在这种情况下,如果您的文件名包含空格,则需要设置 IFS=$'\n' 以避免该问题。我更新了我的答案。
    • IFS=$'\n' arr=( $(cat file | cut -d' ' -f2-) ) 绝不是一个好主意! (这取决于路径名扩展)。使用 Bash≥4:mapfile -t arr &lt; &lt;(cat file | cut -d' ' -f2-)这是 mapfile 的工作。 :)
    • 是的,我明白了。我更新了我的答案以显示差异。谢谢。
    【解决方案2】:

    使用以下任何一种方式传递您的命令: 1) 带切

    cut -d " " -f 2-
    

    2) 使用 sed

    sed -r 's/^[0-9]+ //g'
    

    3) 使用 awk

    awk '{print $2}' /* willnot work if whitespace in filename */
    
    awk 'sub($1,"")' /* will work always */
    

    【讨论】:

    • 如果任何文件名包含空格,则 awk 解决方案将失败。
    • sub($1,"") 总是一个坏主意。想象一下如果$1.*。此外,它将重新编译记录并压缩所有空白字符链,因此它也会因包含制表符或多个连续空格的文件名而失败。
    • @Ed Morton:在这种情况下会有什么影响?根据他的问题,第一列将始终只包含文件大小。如果我的理解有误,请指正。也提供一个例子,以便我理解。谢谢!
    • 当 X 是输入数据时执行sub(X,Y) 通常是要避免的。在这种情况下,我认为您正在修改 $1 但您没有修改,您正在修改 $0 所以它不会像我说的那样压缩空白,它只会留下一个前导空白。不过,您真的应该只使用sub(/[^ ]+ /,"")
    【解决方案3】:

    使用cut的另一种解决方案

    find -type f -printf "%s %p\n" | sort -nr | head -n 4 | cut -d ' ' -f 2
    

    cut 的选项 '-d' 表示分隔符,这里使用空格作为分隔符。但是这个解决方案有局限性。如果文件路径包含空格,则会失败。

    你也可以使用awk

    find -type f -printf "%s %p\n" | sort -nr | head -n 4 | awk "{print $2}"
    

    awk 使用空格作为默认分隔符。如果文件路径包含空格也会失败

    【讨论】:

    • 如果任何文件名包含空格,则 awk 解决方案将失败,如果文件名包含空格,则剪切解决方案也会失败,不要在 awk 脚本周围使用双引号(在这种情况下,$2第二个参数传递给您的外壳,而不是根据需要传递给该行的第二个字段),并且在多个早期答案中都建议了 awk 和 cut 解决方案。
    • 对不起!在我编辑的时候,我没有看到其他答案。感谢您对 awk 中的双引号的建议。
    【解决方案4】:

    使用sed

    使用sed的简单解决方案

    测试:

        $ cat inputFile
        374266 lecture04/address-translation.png
        2629 lecture04/lecture04-display.txt
        1880 lecture04/lecture04-class16.txt
        1828 lecture04/quiz-participation-04.zip
        $ sed -r 's/^[0-9]+\s//g' inputFile
        lecture04/address-translation.png
        lecture04/lecture04-display.txt
        lecture04/lecture04-class16.txt
        lecture04/quiz-participation-04.zip
    

    它的作用

    • -r扩展正则表达式

    • s 替代命令。格式为s/regex/repalcemnt/

    • /^[0-9]+\s//

      • ^[0-9]+\s 匹配任意数量的数字,后跟字符串开头的空格^

      • //这里替换字符串是null,删除数字

    使用 grep

     $ grep -oE '\s.*$' input
     lecture04/address-translation.png
     lecture04/lecture04-display.txt
     lecture04/lecture04-class16.txt
    

    用法

    管道任何命令都会给你输出。

    例如

    find -type f -printf "%s %p\n" | sort -nr | head -n 4 | sed -r 's/[0-9]+\s//g'
    

    【讨论】:

    • 我相信他会希望它通过管道传输,所以应该是:find -type f -printf "%s %p\n" | sort -nr | head -n 4 | sed -r 's/[0-9]+\s//g'
    • 如果文件路径有空格会grep和sed失败?
    • 我永远不会使用 grep 来处理这样的事情,所以我很想知道,但 sed 命令会很好。但是 cut 是适合这项工作的工具。
    • @nu11p01n73R 您介意解释一下 sed 命令中的参数吗?我如何将此输出放入脚本中的预定义数组中?
    • @nu11p01n73R 谢谢!
    猜你喜欢
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 2010-12-01
    相关资源
    最近更新 更多