【问题标题】:Sed through files without using for loop?sed 通过文件而不使用 for 循环?
【发布时间】:2020-11-17 06:36:39
【问题描述】:

我有一个小脚本,它基本上会在我的~/scripts 文件夹中生成一个包含所有脚本的菜单,并且每个脚本旁边都会显示一个描述它的句子,该句子是脚本中被注释掉的第三行。然后,我计划将其通过管道传输到 fzfdmenu 以选择它并开始编辑它或其他任何东西。

1 #!/bin/bash
2
3 # a script to do

所以它看起来像这样

foo.sh      a script to do X
bar.sh      a script to do Y  

目前我让它在脚本文件夹中的所有文件上运行for 循环,然后在所有文件上运行sed -n 3p

for i in $(ls -1 ~/scripts); do
    echo -n "$i"
    sed -n 3p "~/scripts/$i"
    echo 
done | column -t -s '#' | ...

我想知道是否有更有效的方法来做到这一点,它不涉及 for 循环,只使用sed。任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 这里为什么需要ls?你可以做一个for file in ~/scripts/*;,然后简单地sed -n 3p "$file"

标签: bash for-loop awk sed


【解决方案1】:

你可以试试这个awk命令,而不是解析ls输出+sed的循环:

awk 'FNR == 3 {
   f = FILENAME; sub(/^.*\//, "", f); print f, $0; nextfile
}' ~/scripts/* | column -t -s '#' | ...

【讨论】:

  • 我对@9​​87654325@ 没有经验,但是是否可以在上述awk 命令本身中只显示文件名而不显示完整路径,即不依赖像basename 这样的永恒程序?
【解决方案2】:

是的,有一种更有效的方法,但不,它不仅使用sed。虽然这对于您的用例来说可能是一个愚蠢的优化,但它可能还是值得的。

效率低下是您使用ls 读取目录然后解析其输出。对于大型目录,即使您只遍历一次,这也会导致将该列表保存在内存中的大量开销。此外,它没有正确完成,请考虑带有 shell 解释的特殊字符的文件名。

更有效的方法是将find 与其-exec 选项结合使用,该选项会依次使用找到的每个文件启动第二个程序。

顺便说一句:如果您不依赖行号,而是使用标签来标记描述,您也可以使用grep -r,这样可以完全避免每个文件的额外进程。

【讨论】:

    【解决方案3】:

    这可能对你有用(GNU sed):

    sed -sn '1h;3{H;g;s/\n/ /p}' ~/scripts/*
    

    使用-s 选项重置每个文件的行号地址。

    将第 1 行复制到保留空间。

    将第 3 行附加到保留空间。

    交换模式空间的保持空间。

    用空格替换换行符并打印结果。

    将处理目录~/scripts 中的所有文件。

    注意您可能希望用制表符替换空格分隔符或将结果通过管道传递给column 命令。

    【讨论】:

      猜你喜欢
      • 2015-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-04
      • 1970-01-01
      相关资源
      最近更新 更多