【问题标题】:How? Bash loop, sed and inserting the current loop's filename into the sed pattern space如何? Bash 循环、sed 并将当前循环的文件名插入 sed 模式空间
【发布时间】:2013-02-17 01:46:23
【问题描述】:

目标: 要遍历一个文本文件文件夹,请提取所有行尾、自动换行、带连字符的单词,并将它们整理成一个列表。

001.txt be-littled
001.txt dev-eloper
002.txt sand-wich
...

其目的是扫描列表并将有效的连字词与仅包含单词的单词区分开来(即,24 与 dev-eloper)。

我当前的 Bash/sed 脚本正确地捕获了大部分(足够)单词。我知道它需要一些调整(比如当连字符结束段落时)。

但现在,我无法将当前文件名放入模式空间。

for f in *.txt
  do
    sed -rn 'N;/PATTERN/!{D};s:PATTERN:\3-\5\n\7:;P;D' * > output.txt;
  done

..其中 PATTERN = (^.)(+)(.+)(-\n)(\S+)(+)(.$)

for f in *.txt; do sed -rn 'N;/(^.*)( +)(.+)(-\n)(\S+)( +)(.*$)/!{D};s:(^.*)( +)(.+)(-\n)(\S+)( +)(.*$):\3-\5\n\7:;P;D' * > output.txt;done

我尝试将 '"$f"' 放在 \3 之前,但这只是在所有行的最后一页前面(即,'250.txt be-littled')。

我怀疑我的代码并没有完全按照我的想法做。 :-) 也许我不了解 sed 在 bash 中的循环顺序。

我使用的是 Ubuntu 12.10,几周前才开始学习 bash 和 sed。我愿意接受建议。

谢谢,

【问题讨论】:

  • 您能否构建一个更简单的正则表达式示例,以使您问题中的代码更易于阅读?
  • 您应该使用for f in *.txt ; do sed ' ....' $f >> output ; donesed '....' * >> output。您当前的构造每次都通过循环处理所有文件。解决这个问题,然后看看你的问题是什么样的。祝你好运。
  • 您介意举一个您的案例end-of-line, word-wrapped, hyphenated words 的例子吗?行尾和连字符实际上是可以的,但是word-wrapped 是什么意思? 而且,匹配是否应具有所有这些特征,或者其中之一足以限定匹配?

标签: bash sed filenames


【解决方案1】:

我不知道,如何使用 sed 获取当前文件名。如果你不介意使用 perl,试试这个 perl 脚本吧

use strict;
use warnings;

my $hyphen;

while (<>) {
    next if (m/^\s*$/);

    if ($hyphen) {
        m/^\s*(\w+)/;
        print "$1\n";
        $hyphen = 0;
    }

    if (m/(\w+-)\s*$/) {
        print "$ARGV $1";
        $hyphen = 1;
    }
}

此脚本将行的最后一个连字符部分与文件名一起打印并设置一个标志。在下一行中,它查找此标志并打印该行的第一个单词。它还会跳过空行。

你叫它

perl hyphen.pl file1.txt file2.txt ...

【讨论】:

  • 您的代码似乎有效。有些。我没有检查我拥有的所有 254 个文本文件,但我知道第一个连字符出现在 007.txt 上,但是您的代码在 008.txt 上捕获了它的第一个单词。您的代码以正确的单词结束在正确的文件中。此外,在我的页面 036.txt 和 037.txt 之间,我收到一个错误:在 hyphen.pl 第 11 行, 第 1242 行使用未初始化的值 $1 连接 (.) 或字符串。我称您的代码为“hyphen.pl”并使用命令 "perl hyphen.pl *.txt" 运行它。我从来没有用 Perl 编程过。谢谢,我接下来要学习的主题是 Perl 和 awk。 :-)
  • @Dances_with_Wools 我更新了脚本以允许在行尾或行首留出空白。也许这就是这里的问题。当脚本在行尾找到一个连字符时,它希望单词的其余部分位于下一行。
  • 好的。我得到了和以前一样的结果。所以我更仔细地查看了文件 007.txt(您的代码遗漏了)和 037.txt(仍然给出了错误代码)。事实证明,在我的页面 037.txt 上,一行以“sun-”结尾,下一行以“.light”开头。该死的OCR! :-) 并且 007.txt 有两个行尾连字符:“harm-less”。和“中间”我不知道足够的 Perl 来理解你的代码是如何错过它们的。但看起来 244an 用一些额外的 sed 细节解决了我的问题。谢谢。
【解决方案2】:

我不知道word-wrapped 是什么意思,但这可能有效:

grep -oH "[^ ]*-[^ ]*$" *.txt | sed 's/:/ /'

结尾的sed 调用只是为了使输出与您的输出相同——它将grep 添加的第一个: 替换为一个空格。

输出:

$ cat 001.txt 
be-littled
dev-eloper

$ cat 002.txt 
sand-wich

$ grep -oH "[^ ]*-[^ ]*$" *.txt | sed 's/:/ /'
001.txt be-littled
001.txt dev-eloper
002.txt sand-wich

注意:要改进grep 中使用的表达式以适应您的需求,首先需要了解您的需求——我真的没有从@987654328 那里得到这个想法@;

【讨论】:

  • word-wrapped 我的意思是一个词,从一行开始,在下一行继续——我想这就是它的名字。 :-) 您的 grep 命令会捕获单词的第一部分,但不会捕获第二部分。
【解决方案3】:

我不明白为什么您没有成功写入文件名。您写道,您在\3 之前尝试过'"$f"',我认为这应该可行。但是我做了几乎相同的事情,但对整个 sed 命令使用双引号,所以我不必使用 '"..."' 构造。
在写入结果文件时,您还应该使用&gt;&gt; 而不是&gt;,否则您会覆盖循环中每个新文件的结果文件。
这可能是一个错字,但你在 sed 行的末尾有 ... * &gt; output.txt,我认为应该是 $f 而不是 *

对sed命令使用双引号,! {D}!后的空格,&gt;&gt; output.txt$f在替换中写入文件名(也使用@作为替换分隔符以便能够使用&lt;file&gt;: 在结果中):

for f in *.txt; do
  sed -rn "N;/(^.*)( +)(.+)(-\n)(\S+)( +)(.*$)/! {D};s@(^.*)( +)(.+)(-\n)(\S+)( +)(.*$)@$f: \3-\5\n\7@;P;D" $f >> output.txt
done

我还没有查看您的模式,但是当我测试它时,它似乎很有效。

我在两个小文件上进行了尝试,一个包含您问题中的换行词,另一个包含一些带有“虚拟词”的行。

[]$ cat tf1.txt
asdf asdf be-
littled asdf asdf
asfd dev-
eloper asdf sand-
wich asdf asdf.
[]$ cat tf2.txt
asfd abc-
de lsdk laskfjd
asdf asdf 1234-
56 sdl sdg
sdfg

输出:

[]$ ./tfwordwrap.sh
tf1.txt: be-littled
tf1.txt: dev-eloper
tf1.txt: sand-wich
tf2.txt: abc-de
tf2.txt: 1234-56

【讨论】:

  • 做到了。我不知道“>>”。我可能已经多次解决了我的问题,但第二次“>”。 :-) 是的,最后的 * 是 $f 多次。但是,当我将所有内容都用双引号括起来时,我得到了“bash: !{D}: event not found”错误。但是单引号工作得很好。而“@”帮助我的输出看起来更好。谢谢,2周的断断续续的砸头到此结束。
  • 我正在使用脚本对此进行测试,似乎!{D} 没问题。从命令行时,!{D} 之间必须有一个空格。 !{...} 可能意味着要抨击,不知道是什么。我相应地编辑了我的答案。因此,如果您更改为! {D},您可以在整个 sed 命令中使用双引号。
猜你喜欢
  • 2017-10-17
  • 2013-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多