用 Linux 命令行解决 Wordle 问题
游戏 grep
![](/data/attachment/album/202202/08/122231xjp7p87y6pri8kp0.jpg "Linux keys on the keyboard for a desktop computer")



> 
> 使用 Linux 的 grep 和 fgrep 命令来赢得你最喜欢的基于单词的猜测游戏。
> 
> 
> 


我最近有点迷恋上了一个在线单词猜谜游戏，在这个游戏中，你有六次机会来猜一个随机的五个字母的单词。这个词每天都在变化，而且你每天只能玩一次。每次猜测后，你猜测中的每个字母都会被高亮显示：灰色表示该字母没有出现在神秘单词中，黄色表示该字母出现在单词中，但不在那个位置，绿色表示该字母出现在单词中的那个正确位置。


下面是你如何使用 Linux 命令行来帮助你玩像 Wordle 这样的猜测游戏。我用这个方法来帮助我解决 1 月 6 日的谜题：


### 第一次尝试


Linux 系统在 `/usr/share/dict/words` 文件中保存了一个单词词典。这是一个很长的纯文本文件。我的系统的单词文件里有超过 479,800 个条目。该文件既包含纯文本，也包含专有名词（名字、地点等等）。


为了开始我的第一次猜测，我只想得到一个长度正好是五个字母的纯文本词的列表。要做到这一点，我使用这个 `grep` 命令：



```
$ grep '^[a-z][a-z][a-z][a-z][a-z]$' /usr/share/dict/words > myguess

```

`grep` 命令使用正则表达式来进行搜索。你可以用正则表达式做很多事情，但为了帮助我解决 Wordle 问题，我只需要基本的东西。`^` 表示一行的开始，`$` 表示一行的结束。在两者之间，我指定了五个 `[a-z]` 的实例，表示从 a 到 z 的任何小写字母。


我还可以使用 `wc` 命令来查看我的可能单词列表，“只有” 15,000 个单词：



```
$ wc -l myguess
15034 myguess

```

从这个列表中，我随机挑选了一个五个字母的单词：`acres`。`a` 被设置为黄色，意味着该字母存在于神秘单词的某处，但不在第一位置。其他字母是灰色的，所以我知道它们并不存在于今天的单词中。


![acres word attempt](/data/attachment/album/202202/08/121439skac6467c00p4e52.png "acres word attempt")


### 第二次尝试


对于我的下一个猜测，我想得到一个包含 `a` 的所有单词的列表，但不是在第一位置。我的列表也不应该包括字母 `c`、`r`、`e` 或 `s`。让我们把这个问题分解成几个步骤。


为了得到所有带 a 的单词的列表，我使用 `fgrep`（固定字符串 grep）命令。`fgrep` 命令也像 `grep` 一样搜索文本，但不使用正则表达式：



```
$ fgrep a myguess > myguess2

```

这使我的下一个猜测的可能列表从 15,000 个字下降到 6,600 个字：



```
$ wc -l myguess myguess2
 15034 myguess
  6634 myguess2
 21668 total

```

但是这个单词列表中的第一个位置也有字母 `a`，这是我不想要的。游戏已经表明字母 `a` 存在于其他位置。我可以用 `grep` 修改我的命令，以寻找在第一个位置包含其他字母的词。这就把我可能的猜测缩小到了 5500 个单词：



```
$ fgrep a myguess | grep '^[b-z]' > myguess2
$ wc -l myguess myguess2
 15034 myguess
  5566 myguess2
 20600 total

```

但我知道这个神秘的词也不包括字母 `c`、`r`、`e` 或 `s`。我可以使用另一个 `grep` 命令，在搜索中省略这些字母：



```
$ fgrep a myguess | grep '^[b-z]' | grep -v '[cres]' > myguess2
$ wc -l myguess myguess2
15034 myguess
 1257 myguess2
16291 total

```

`-v` 选项意味着反转搜索，所以 `grep` 将只返回不符合正则表达式 `[cres]` 或单列字母 `c`、`r`、`e` 或 `s` 的行。有了这个额外的 `grep` 命令，我把下一个猜测的范围大大缩小到只有 1200 个可能的单词，这些单词在某处有一个 `a`，但不在第一位置，并且不包含 `c`、`r`、`e`、或 `s`。


在查看了这个列表后，我决定尝试一下 `balmy` 这个词。


![balmy word attempt](/data/attachment/album/202202/08/121440pluqoifa0peuf80j.png "balmy word attempt")


### 第三次尝试


这一次，字母 `b` 和 `a` 被高亮显示为绿色，意味着我把这些字母放在了正确的位置。字母 `l` 是黄色的，所以这个字母存在于单词的其他地方，但不是在那个位置。字母 `m` 和 `y` 是灰色的，所以我可以从我的下一个猜测中排除这些。


为了确定下一个可能的单词列表，我可以使用另一组 `grep` 命令。我知道这个词以 `ba` 开头，所以我可以从这里开始搜索：



```
$ grep '^ba' myguess2 > myguess3
$ wc -l myguess3
77 myguess3

```

这只有 77 个词! 我可以进一步缩小范围，寻找除第三位外还包含字母 `l` 的词：



```
$ grep '^ba[^l]' myguess2 > myguess3
$ wc -l myguess3
61 myguess3

```

方括号 `[^l]` 内的 `^` 表示不是这个字母列表，即不是字母 `l`。这使我的可能单词列表达到 61 个，并非所有的单词都包含字母 `l`，我可以用另一个 `grep` 搜索来消除这些单词：



```
$ grep '^ba[^l]' myguess2 | fgrep l > myguess3
$ wc -l myguess3
10 myguess3

```

这些词中有些可能包含字母 `m` 和 `y`，而这些字母并不在今天的神秘词中。我可以再进行一次反转 `grep` 搜索，将它们从我的猜测列表中删除：



```
$ grep '^ba[^l]' myguess2 | fgrep l | grep -v '[my]' > myguess3
$ wc -l myguess3
7 myguess3

```

我的可能的单词列表现在非常短，只有七个单词!



```
$ cat myguess3
babul
bailo
bakal
bakli
banal
bauld
baulk

```

我选择 `banal` 作为我下一次猜测的可能的词，而这恰好是正确的。


![banal word attempt](/data/attachment/album/202202/08/121440u3qadwak7q7h5aca.png "banal word attempt")


### 正则表达式的力量


Linux 的命令行提供了强大的工具来帮助你完成实际工作。`grep` 和 `fgrep` 命令在扫描单词列表方面提供了极大的灵活性。对于一个基于单词的猜测游戏，`grep` 帮助识别了一个包含 15000 个可能的单词的列表。在猜测并知道哪些字母出现在神秘的单词中，哪些没有，`grep` 和 `fgrep` 帮助将选项缩小到 1200 个单词，然后只剩下 7 个单词。这就是命令行的力量。




---


via: <https://opensource.com/article/22/1/word-game-linux-command-line>


作者：[Jim Hall](https://opensource.com/users/jim-hall) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
I've recently become a little obsessed with an online word puzzle game in which you have six attempts to guess a random five-letter word. The word changes every day, and you can only play once per day. After each guess, each of the letters in your guess is highlighted: gray means that letter does not appear in the mystery word, yellow means that letter appears in the word but not at that position, and green means the letter appears in the word at that correct position.


Here's how you can use the Linux command line to help you play guessing games like Wordle. I used this method to help me solve the January 6 puzzle:

## First try

Linux systems keep a dictionary of words in the `/usr/share/dict/words`

file. This is a very long plain text file. My system's words file has over 479,800 entries in it. The file contains both plain words and proper nouns (names, places, and so on).

To start my first guess, I just want a list of plain words that are exactly five letters long. To do that, I use this `grep`

command:

`$ grep '^[a-z][a-z][a-z][a-z][a-z]$' /usr/share/dict/words > myguess`


The `grep`

command uses regular expressions to perform searches. You can do a lot with regular expressions, but to help me solve Wordle, I only need the basics: The `^`

means the start of a line, and the `$`

means the end of a line. In between, I've specified five instances of `[a-z]`

, which indicates any lowercase letter from a to z.

I can also use the `wc`

command to see my list of possible words is "only" 15,000 words:

```
$ wc -l myguess
15034 myguess
```


From that list, I picked a random five-letter word: *acres*. The *a* was set to yellow, meaning that letter exists somewhere in the mystery word but not in the first position. The other letters are gray, so I know they don't exist in the word of the day.

![acres word attempt acres word attempt](https://opensource.com/sites/default/files/acres.png)

Jim Hall (CC BY-SA 4.0)

## Second try

For my next guess, I want to get a list of all words that contain an *a*, but not in the first position. My list should also not include the letters *c*,* r*, *e*, or *s*. Let's break this down into steps:

To get a list of all words with an a, I use the `fgrep`

(fixed strings grep) command. The `fgrep`

command also searches for text like `grep`

, but without using regular expressions:

`$ fgrep a myguess > myguess2`


That brings my possible list of next guesses down from 15,000 words to 6,600 words:

```
$ wc -l myguess myguess2
15034 myguess
6634 myguess2
21668 total
```


But that list of words also includes the letter *a* in the first position, which I don't want. The game already indicated the letter *a* exists in some other position. I can modify my command with `grep`

to look for words containing some other letter in the first position. That narrows my possible guesses to just 5,500 words:

```
$ fgrep a myguess | grep '^[b-z]' > myguess2
$ wc -l myguess myguess2
15034 myguess
5566 myguess2
20600 total
```


But I know the mystery word also does not include the letters *c*, *r*, *e*, or *s*. I can use another `grep`

command to omit those letters from the search:

```
$ fgrep a myguess | grep '^[b-z]' | grep -v '[cres]' > myguess2
$ wc -l myguess myguess2
15034 myguess
1257 myguess2
16291 total
```


The `-v`

option means to invert the search, so `grep`

will only return the lines that do not match the regular expression `[cres]`

or the single list of letters *c*, *r*, *e*, or *s*. With this extra `grep`

command, I've narrowed my next guess considerably to only 1,200 possible words with an a somewhere but not in the first position, and that do not contain *c*, *r*, *e*, or *s*.

After viewing the list, I decided to try the word *balmy*.

![balmy word attempt balmy word attempt](https://opensource.com/sites/default/files/balmy.png)

Jim Hall (CC BY-SA 4.0)

## Third try

This time, the letters *b* and *a* were highlighted in green, meaning I have those letters in the correct position. The letter* l* was yellow, so that letter exists somewhere else in the word, but not in that position. The letters *m* and *y* are gray, so I can eliminate those from my next guess.

To identify my next list of possible words, I can use another set of `grep`

commands. I know the word starts with *ba*, so I can begin my search there:

```
$ grep '^ba' myguess2 > myguess3
$ wc -l myguess3
77 myguess3
```


That's only 77 words! I can narrow that further by looking for words that also contain the letter *l* in anywhere but the third position:

```
$ grep '^ba[^l]' myguess2 > myguess3
$ wc -l myguess3
61 myguess3
```


The `^`

inside the square brackets` [^l]`

means not this list of letters, so not the letter *l*. That brings my list of possible words to 61, not all of which contain the letter *l*, which I can eliminate using another `grep`

search:

```
$ grep '^ba[^l]' myguess2 | fgrep l > myguess3
$ wc -l myguess3
10 myguess3
```


Some of those words might contain the letters *m* and *y*, which are not in today's mystery word. I can remove those from my list of guesses with one more inverted `grep`

search:

```
$ grep '^ba[^l]' myguess2 | fgrep l | grep -v '[my]' > myguess3
$ wc -l myguess3
7 myguess3
```


My list of possible words is very short now, only seven words!

```
$ cat myguess3
babul
bailo
bakal
bakli
banal
bauld
baulk
```


I'll pick *banal* as a likely word for my next guess, which happened to be correct.

![banal word attempt banal word attempt](https://opensource.com/sites/default/files/banal.png)

Jim Hall (CC BY-SA 4.0)

## The power of regular expressions

The Linux command line provides powerful tools to help you do real work. The `grep`

and `fgrep`

commands offer great flexibility in scanning lists of words. For a word-based guessing game, `grep`

helped identify a list of 15,000 possible words of the day. After guessing and knowing what letters did and did not appear in the mystery word, `grep`

and `fgrep`

helped narrow the options to 1,200 words and then only seven words. That's the power of the command line.

## 1 Comment