【问题标题】:Concating string with shell script with accumulator将字符串与带有累加器的 shell 脚本连接起来
【发布时间】:2012-12-05 16:33:45
【问题描述】:

我想将一个以“\n”分隔的列表转换为另一个以空格分隔的列表。 前任: 获取像 ispell 英语词典这样的词典。 http://downloads.sourceforge.net/wordlist/ispell-enwl-3.1.20.zip

我最初的想法是使用变量作为累加器:

a=""; cat american.0 | while read line; do a="$a $line"; done; echo $a

... 但它会产生 '\n' 字符串!!!

问题:

  1. 为什么它不起作用?
  2. 这样做的正确方法是什么?

    谢谢。

【问题讨论】:

  • 你试过了吗:cat american.0 | tr '\n' ' '
  • 除了“无用使用cat”位(tr '\n' ' ' < american.0 会避免这种情况),tr 怎么不起作用?
  • 我不知道。也许 tr 的 mac os X 版本不能正常工作。 $tr '\n' ' '

标签: string shell accumulator


【解决方案1】:

问题是当你有管道时:

command_1 | command_2

每个命令都在单独的子 shell 中运行,并带有父环境的单独副本。因此,该命令创建的任何变量,或它对现有变量所做的任何修改,都不会被包含的 shell 感知。

在您的情况下,您实际上并不需要管道,因为:

cat filename | command

在您需要的所有方面都等同于:

command < filename

所以你可以写:

a=""; while read line; do a="$a $line"; done < american.0; echo $a

避免创建任何子shell。

也就是说,根据this StackOverflow answer,您不能真正依赖能够容纳超过 1-4KB 数据的 shell 变量,因此您可能需要重新考虑您的整体方法。将整个单词列表存储在 shell 变量中可能不起作用,即使这样做,也可能不起作用很好


编辑添加:要创建一个名为/tmp/american.tmp 的临时文件,其中包含变量$a 的内容,您可以编写:

while IFS= read -r line; do
  printf %s " $line"
done < american.0 > /tmp/american.tmp

【讨论】:

  • 那行有问题:-bash: syntax error near unexpected token `do' 所以,我重写了:a="";而 IFS= 读取 -r 行;做 a="$a $line";回声$a;完成
  • 感谢@ruakh。我正在尝试使用临时文件。一个="";而 IFS= 读取 -r 行;做一个="${line%\\n}";回声 $a >> /tmp/american.tmp;回声$a;完成
  • @rdlllopes:回复:语法错误:糟糕,有趣。我已经确定了我的答案。回复:您的临时文件版本:换行符来自echo。要禁用它们,请使用echo -n,或者更便携的printf %s。 (另外,大部分代码都是无关的。你可以写while IFS= read -r line; do printf %s " $line"; done &lt; american.0 &gt; /tmp/american.tmp。)
  • 现在我明白了。我在这里发现了一个隐含的问题。 iSpell 文件是 Windows 文本(我没想到会这样)。每行都有一个“回车”。使用 printf %s " $line" 将返回一个空白文件,因为每一行都会覆盖前一行。这就是为什么 tr '\n' 建议不起作用的同一个问题。删除 '\r',一切正常。感谢所有答案。
【解决方案2】:

如果你想用空格替换'\n',你可以简单地使用tr,如下:

a=$(tr '\n' ' ' < american.0)

【讨论】:

  • 完美运行,在美国 0 中删除 '\r' 之前。谢谢。但是,正如@ruakh 告诉我的,可变大小是有限制的。
猜你喜欢
  • 2016-05-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多