【问题标题】:How can I read words (instead of lines) from a file?如何从文件中读取单词(而不是行)?
【发布时间】:2012-06-07 12:36:19
【问题描述】:

我已经阅读了this question 关于如何使用 bash 从文本文件中读取 n 个字符的信息。我想知道如何从文件中一次读取一个单词:

example text
example1 text1
example2 text2
example3 text3

谁能给我解释一下,或者给我一个简单的例子? 谢谢!

【问题讨论】:

    标签: bash


    【解决方案1】:

    read 命令默认读取整行。所以解决方案可能是读取整行,然后将其拆分为空格,例如for:

    #!/bin/sh
    
    while read line; do
        for word in $line; do
            echo "word = '$word'"
        done
    done <"myfile.txt"
    

    【讨论】:

    • 在上面的代码中我的文件名应该在哪里?
    • @Admia 请记住,read 从标准输入读取。解决它的“最佳”方法(IMO)是将代码放入函数中。而且由于函数可以像任何其他命令一样被调用,它也可以与重定向一起使用。那么你可以做例如function_with_read_loop &lt; some_file.
    • 如果您的行包含* 作为独立元素,您将从for word in $line 获得当前目录中的文件名列表。 (另外,没有-rread 将使用反斜杠文字)。
    【解决方案2】:

    使用标准输入执行此操作的方法是将-a 标志传递给读取:

    read -a words
    echo "${words[@]}"
    

    这会将您的整行读入索引数组变量,在本例中名为 words。然后,您可以使用 shell parameter expansionswords 执行任何您喜欢的数组操作。

    对于面向文件的操作,当前版本的 Bash 还支持映射文件built-in。例如:

    mapfile < /etc/passwd
    echo ${MAPFILE[0]}
    

    无论哪种方式,数组都是要走的路。值得您花时间熟悉 Bash array syntax 以充分利用此功能。

    【讨论】:

    • 这个问题被标记为 bash,但对于未来的读者,请注意这些都是 bash 特定的,在 posix shell 中不起作用。
    【解决方案3】:

    通常,您应该使用while read -r line 循环从文件中读取。为此并解析行中的单词需要在while 循环内嵌套一个for 循环。

    这是一种无需嵌套循环即可工作的技术:

    for word in $(<inputfile)
    do
        echo "$word"
    done
    

    【讨论】:

    • 我不会说字符串拆分“通常”是正确的。如果您的文件中有*,您将在输出中获得当前目录中的名称列表。
    • @CharlesDuffy:这个问题也会影响接受的答案(我第二句话中描述的技术)。我的代码 sn-p 中的技术以同样的方式失败。
    【解决方案4】:

    在给定的上下文中,单词的数量是已知的:

    while read -r word1 word2 _; do
      echo "Read a line with word1 of $word1 and word2 of $word2"
    done
    

    如果您想将每一行读入一个数组,read -a 会将第一个单词放入数组的元素 0,将第二个单词放入元素 1,依此类推:

    while read -r -a words; do
      echo "First word is ${words[0]}; second word is ${words[1]}"
      declare -p words # print the whole array
    done
    

    【讨论】:

      【解决方案5】:

      在 bash 中,只需使用空格作为分隔符 (read -d ' ')。此方法需要一些预处理以将换行符转换为空格(使用tr)并将多个空格合并为一个(使用sed):

      {
       tr '\n' ' ' | sed 's/  */ /g' | while read -d ' ' WORD
       do
        echo -n "<${WORD}> "
       done
       echo
      } << EOF
      Here you have some words, including * wildcards
      that don't get expanded,
      multiple   spaces   between   words,
          and lines with spaces at the begining.
      EOF
      

      此方法的主要优点是您无需担心数组语法,只需使用 for 循环即可,但无需通配符扩展。

      【讨论】:

        【解决方案6】:

        我遇到了这个问题和建议的答案,但我没有看到列出这个简单的可能解决方案:

        for word in `cat inputfile`
        do
          echo $word
        done
        

        【讨论】:

        • 这里没有列出是有充分理由的:它非常有问题。如果您的输入文件中包含*,您将在输出中获得当前目录中的文件列表——并且因为echo 的参数没有被引用,如果您的文件名之一拆分为包含 glob 的单词集,该 glob会被扩展。另请参阅Why you don't read lines with for
        【解决方案7】:

        这也可以使用 AWK 来完成:

        awk '{for(i=1;i<=NF;i++) {print $i}}' text_file
        

        【讨论】:

          【解决方案8】:

          您可以将xargs(读取由空格换行符分隔的单词)和echo结合起来,每行打印一个:

          <some-file xargs -n1 echo
          
          some-command | xargs -n1 echo
          

          这也适用于大型或慢速数据流,因为它不需要一次读取整个输入。

          我用它从 SQLite 中一次读取 1 个表名,它在列布局中打印表名:

          sqlite3 db.sqlite .tables | xargs -n1 echo | while read table; do echo "1 table: $table"; done
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-04-15
            • 2021-03-17
            • 2020-12-16
            • 1970-01-01
            • 2017-06-14
            • 1970-01-01
            • 2016-01-12
            • 1970-01-01
            相关资源
            最近更新 更多