【问题标题】:Each word on a separate line每个单词单独一行
【发布时间】:2012-11-09 02:16:57
【问题描述】:

我有一句话像

这个例子

我想把它写到一个文件中,这样这个句子中的每个单词都被写到一个单独的行中。

如何在 shell 脚本中做到这一点?

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    几种方法,选择你最喜欢的!

    echo "This is for example" | tr ' ' '\n' > example.txt
    

    或者干脆这样做以避免不必要地使用echo:

    tr ' ' '\n' <<< "This is for example" > example.txt
    

    &lt;&lt;&lt; 表示法与herestring 一起使用

    或者,使用sed 代替tr:

    sed "s/ /\n/g" <<< "This is for example" > example.txt
    

    更多替代方案,请查看其他人的答案 =)

    【讨论】:

      【解决方案2】:
      $ echo "This is for example" | xargs -n1
      This
      is
      for
      example
      

      【讨论】:

        【解决方案3】:

        尝试使用:

        string="This is for example"
        
        printf '%s\n' $string > filename.txt
        

        或利用 分词

        string="This is for example"
        
        for word in $string; do
            echo "$word"
        done > filename.txt
        

        【讨论】:

        • 谢谢!我希望将其写入文件。该怎么做?
        • 您可以在带有done &gt; filename.txt 的循环版本上使用单个I/O 重定向(这可以保证文件被截断并且只包含来自$string 的数据,而&gt;&gt; 符号将离开filename.txt 之前的所有内容均未更改,新材料附加在末尾。
        【解决方案4】:
        example="This is for example"
        printf "%s\n" $example
        

        【讨论】:

        • 单线:printf "%s\n" This is the example
        【解决方案5】:

        尝试使用:

        str="This is for example"
        echo -e ${str// /\\n} > file.out
        

        输出

        > cat file.out 
        This
        is
        for
        example
        

        【讨论】:

          【解决方案6】:

          使用fmt 命令

          >> echo "This is for example" | fmt -w1 > textfile.txt ; cat textfile.txt
          This
          is
          for
          example
          

          有关fmt 及其选项的完整描述,请查看related man page。

          【讨论】:

            【解决方案7】:

            注意我在几份草稿中写了这个,简化了正则表达式,所以如果有任何不一致,这可能就是原因。

            你关心标点符号吗?例如,在某些调用中,您会看到例如一个像 (etc) 这样的“单词”,就像括号一样。或者这个词是“括号”。而不是“括号”。如果您正在解析包含正确句子的文件,这可能会出现问题,尤其是如果您想按单词排序甚至获取每个单词的字数。

            有一些方法可以解决这个问题,但有一些注意事项,当然还有改进的余地。这些恰好与数字、破折号(以数字表示)和小数点/点(以数字表示)有关。也许有一套确切的规则可以帮助解决这个问题,但下面的例子可以给你一些工作要做。我制作了一些人为的输入示例来演示这些缺陷(或任何你想称它们的名称)。

            $ echo "This is an example sentence with punctuation marks and digits i.e. , . ; \! 7 8 9" | grep -o -E '\<[A-Za-z0-9.]*\>'
            This
            is
            an
            example
            sentence
            with
            punctuation
            marks
            and
            digits
            i.e
            7
            8
            9
            

            如您所见,i.e.` 原来只是 i.e,否则不会显示标点符号。好的,但这忽略了诸如 major.minor.revision-release 形式的版本号之类的东西,例如0.0.1-1;这也可以显示吗?是的:

            $ echo "The current version is 0.0.1-1. The previous version was current from 2017-2018."|grep -o -E '\<[-A-Za-z0-9.]*\>'
            The
            current
            version
            is
            0.0.1-1
            The
            previous
            version
            was
            current
            from
            2017-2018
            

            注意句子不以句号结尾。如果在年份和破折号之间添加一个空格会发生什么?你不会有破折号,但每年都会有自己的路线:

            $ echo "2017 - 2018" | grep -o -E '\<[-A-Za-z0-9.]*\>'
            2017
            2018
            

            那么问题就变成了您是否希望自己计算-;由于分隔单词的性质,如果有空格,您将不会将年份作为单个字符串。因为它本身不是一个词,我认为不会。

            我相信这些可以进一步简化。此外,如果您根本不需要任何标点符号或数字,您可以将其更改为:

            $ echo "The current version is 0.0.1-1. The previous version was current from 2017-2018."|grep -o -E '\<[A-Za-z]*\>'
            The
            current
            version
            is
            The
            previous
            version
            was
            current
            from
            

            如果你想要数字:

            $ echo "The current version is 0.0.1-1. The previous version was current from 2017-2018."|grep -o -E '\<[A-Za-z0-9]*\>'
            The
            current
            version
            is
            0
            0
            1
            1
            The
            previous
            version
            was
            current
            from
            2017
            2018
            

            至于同时包含字母和数字的“单词”,这是另一件事,可能会或可能不会考虑,但可以证明上述内容:

            $ echo "The current version is 0.0.1-1. test1."|grep -o -E '\<[A-Za-z0-9]*\>'
            The
            current
            version
            is
            0
            0
            1
            1
            test1
            

            输出它们。但以下没有(因为它根本不考虑数字):

            $ echo "The current version is 0.0.1-1. test1."|grep -o -E '\<[A-Za-z]*\>'
            The
            current
            version
            is
            

            忽略标点符号很容易,但在某些情况下可能需要或渴望它们。在 eg 的情况下,我想您可以使用 say sed 将 eg 之类的行更改为 eg 但这将是个人喜好,我猜.

            我可以总结一下它是如何工作的,但只是;我累得连想都不想:

            它是如何工作的?

            我将只解释调用grep -o -E '\&lt;[-A-Za-z0-9.]*\&gt;',但其他大部分是相同的(扩展 grep 中的竖线/竖线符号允许多个模式):

            -o 选项仅用于打印匹配项而不是整行。 -E 用于扩展 grep(也可以使用 egrep)。至于正则表达式本身:

            &lt;\ 和 \&gt; 是单词边界(分别开始和结束 - 如果需要,您可以只指定一个);我相信-w 选项与指定两者相同,但调用可能有点不同(我实际上不知道)。

            '\&lt;[-A-Za-z0-9.]*\&gt;' 表示破折号、大小写字母和点零次或多次。至于为什么又把eg变成了.eg,我这个时候只能说是模式,但我没有能力去多想。

            词频计数的奖励脚本

            #!/bin/bash
            
            if [ $# -eq 0 ]; then
                echo "Usage: $(basename ${0}) <FILE> [FILE...]"
                exit 1
            fi
            
            for file do
                if [ -e "${file}" ]
                then
                    echo "** ${file}: "
                    grep -o -E '\<[-A-Za-z0-9.]*\>' "${file}"|sort | uniq -c | sort -rn
                else
                echo >&2 "${1}: file not found"
                continue
                fi
            done
            

            例子:

            $ cat example 
            The current version is 0.0.1-1 but the previous version was non-existent.
            
            This sentence contains an abbreviation i.e. e.g. (so actually two abbreviations).
            
            This sentence has no numbers and no punctuation  
            $ ./wordfreq example 
            ** example: 
               2 version
               2 sentence
               2 no
               2 This
               1 was
               1 two
               1 the
               1 so
               1 punctuation
               1 previous
               1 numbers
               1 non-existent
               1 is
               1 i.e
               1 has
               1 e.g
               1 current
               1 contains
               1 but
               1 and
               1 an
               1 actually
               1 abbreviations
               1 abbreviation
               1 The
               1 0.0.1-1
            

            注意我没有将大写字母转写为小写字母,因此“The”和“the”这两个词显示为不同的词。如果您希望它们全部为小写,您可以在排序之前将脚本中的 grep 调用更改为管道:

                grep -o -E '\<[-A-Za-z0-9.]*\>' "${file}"|tr '[A-Z]' '[a-z]'|sort | uniq -c | sort -rn
            

            哦,既然您问是否要将其写入文件,您可以将其添加到 命令行(用于原始调用):

            > output_file
            

            对于脚本,您可以像这样使用它:

            $ ./wordfreq file1 file2 file3 > output_file
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-08-29
              • 1970-01-01
              • 1970-01-01
              • 2021-05-26
              • 1970-01-01
              • 1970-01-01
              • 2021-10-30
              相关资源
              最近更新 更多