Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu Wang 2019-10-03 09:26:54 +08:00
commit baa0f94f9b
5 changed files with 747 additions and 341 deletions

View File

@ -0,0 +1,77 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Fedora projects for Hacktoberfest)
[#]: via: (https://fedoramagazine.org/fedora-projects-for-hacktoberfest/)
[#]: author: (Ben Cotton https://fedoramagazine.org/author/bcotton/)
Fedora projects for Hacktoberfest
======
![][1]
Its October! That means its time for the annual [Hacktoberfest][2] presented by DigitalOcean and DEV. Hacktoberfest is a month-long event that encourages contributions to open source software projects. Participants who [register][3] and submit at least four pull requests to GitHub-hosted repositories during the month of October will receive a free t-shirt.
In a recent Fedora Magazine article, I listed some areas where would-be contributors could [get started contributing to Fedora][4]. In this article, I highlight some specific projects that provide an opportunity to help Fedora while you participate in Hacktoberfest.
### Fedora infrastructure
* [Bodhi][5] — When a package maintainer builds a new version of a software package to fix bugs or add new features, it doesnt go out to users right away. First it spends time in the updates-testing repository where in can receive some real-world usage. Bodhi manages the flow of updates from the testing repository into the updates repository and provides a web interface for testers to provide feedback.
* [the-new-hotness][6] — This project listens to [release-monitoring.org][7] (which is also on [GitHub][8]) and opens a Bugzilla issue when a new upstream release is published. This allows package maintainers to be quickly informed of new upstream releases.
* [koschei][9] — koschei enables continuous integration for Fedora packages. It is software for running a service for scratch-rebuilding RPM packages in Koji instance when their build-dependencies change or after some time elapses.
* [MirrorManager2][10] — Distributing Fedora packages to a global user base requires a lot of bandwidth. Just like developing Fedora, distributing Fedora is a collaborative effort. MirrorManager2 tracks the hundreds of public and private mirrors and routes each user to the “best” one.
* [fedora-messaging][11] — Actions within the Fedora community—from source code commits to participating in IRC meetings to…lots of things—generate messages that can be used to perform automated tasks or send notifications. fedora-messaging is the tool set that makes sending and receiving these messages possible.
* [fedocal][12] — When is that meeting? Which IRC channel was it in again? Fedocal is the calendar system used by teams in the Fedora community to coordinate meetings. Not only is it a good Hacktoberfest project, its also [looking for a new maintainer][13] to adopt it.
In addition to the projects above, the Fedora Infrastructure team has highlighted [good Hacktoberfest issues][14] across all of their GitHub projects.
### Community projects
* [bodhi-rs][15] — This project provides Rust bindings for Bodhi.
* [koji-rs][16] — Koji is the system used to build Fedora packages. Koji-rs provides bindings for Rust applications.
* [fedora-rs][17] — This project provides a Rust library for interacting with Fedora services like other languages like Python have.
* [feedback-pipeline][18] — One of the current Fedora Council objectives is [minimization][19]: work to reduce the installation and patching footprint of Fedora releases. feedback-pipeline is a tool developed by this team to generate reports of RPM sizes and dependencies.
### And many more
The projects above are only a small sample focused on software used to build Fedora. Many Fedora packages have upstreams hosted on GitHub—too many to list here. The best place to start is with a project thats important to you. Any contributions you make help improve the entire open source ecosystem. If youre looking for something in particular, the [Join Special Interest Group][20] can help. Happy hacking!
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/fedora-projects-for-hacktoberfest/
作者:[Ben Cotton][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://fedoramagazine.org/author/bcotton/
[b]: https://github.com/lujun9972
[1]: https://fedoramagazine.org/wp-content/uploads/2019/09/hacktoberfest-816x345.jpg
[2]: https://hacktoberfest.digitalocean.com/
[3]: https://hacktoberfest.digitalocean.com/register
[4]: https://fedoramagazine.org/how-to-contribute-to-fedora/
[5]: https://github.com/fedora-infra/bodhi
[6]: https://github.com/fedora-infra/the-new-hotness
[7]: https://release-monitoring.org/
[8]: https://github.com/release-monitoring/anitya
[9]: https://github.com/fedora-infra/koschei
[10]: https://github.com/fedora-infra/mirrormanager2
[11]: https://github.com/fedora-infra/fedora-messaging
[12]: https://github.com/fedora-infra/fedocal
[13]: https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/message/GH4N3HYJ4ARFRP666O6EQCHDIQMXVUJB/
[14]: https://github.com/orgs/fedora-infra/projects/4
[15]: https://github.com/ironthree/bodhi-rs
[16]: https://github.com/ironthree/koji-rs
[17]: https://github.com/ironthree/fedora-rs
[18]: https://github.com/minimization/feedback-pipeline
[19]: https://docs.fedoraproject.org/en-US/minimization/
[20]: https://fedoraproject.org/wiki/SIGs/Join

View File

@ -1,5 +1,5 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: translator: (wxy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )

View File

@ -1,340 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (wenwensnow)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Hone advanced Bash skills by building Minesweeper)
[#]: via: (https://opensource.com/article/19/9/advanced-bash-building-minesweeper)
[#]: author: (Abhishek Tamrakar https://opensource.com/users/tamrakarhttps://opensource.com/users/dnearyhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/marcobravo)
Hone advanced Bash skills by building Minesweeper
======
The nostalgia of classic games can be a great source for mastering
programming. Deep dive into Bash with Minesweeper.
![bash logo on green background][1]
I am no expert on teaching programming, but when I want to get better at something, I try to find a way to have fun with it. For example, when I wanted to get better at shell scripting, I decided to practice by programming a version of the [Minesweeper][2] game in Bash.
If you are an experienced Bash programmer and want to hone your skills while having fun, follow along to write your own version of Minesweeper in the terminal. The complete source code is found in this [GitHub repository][3].
### Getting ready
Before I started writing any code, I outlined the ingredients I needed to create my game:
1. Print a minefield
2. Create the gameplay logic
3. Create logic to determine the available minefield
4. Keep count of available and discovered (extracted) mines
5. Create the endgame logic
### Print a minefield
In Minesweeper, the game world is a 2D array (columns and rows) of concealed cells. Each cell may or may not contain an explosive mine. The player's objective is to reveal cells that contain no mine, and to never reveal a mine. Bash version of the game uses a 10x10 matrix, implemented using simple bash arrays.
First, I assign some random variables. These are the locations that mines could be placed on the board. By limiting the number of locations, it will be easy to build on top of this. The logic could be better, but I wanted to keep the game looking simple and a bit immature. (I wrote this for fun, but I would happily welcome your contributions to make it look better.)
The variables below are some default variables, declared to call randomly for field placement, like the variables a-g, we will use them to calculate our extractable mines:
```
# variables
score=0 # will be used to store the score of the game
# variables below will be used to randomly get the extract-able cells/fields from our mine.
a="1 10 -10 -1"
b="-1 0 1"
c="0 1"
d="-1 0 1 -2 -3"
e="1 2 20 21 10 0 -10 -20 -23 -2 -1"
f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 -3 -2 -1"
g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7"
#
# declarations
declare -a room  # declare an array room, it will represent each cell/field of our mine.
```
Next, I print my board with columns (0-9) and rows (a-j), forming a 10x10 matrix to serve as the minefield for the game. (M[10][10] is a 100-value array with indexes 0-99.) If you want to know more about Bash arrays, read [_You don't know Bash: An introduction to Bash arrays_][4].
Lets call it a function, **plough,**  we print the header first: two blank lines, the column headings, and a line to outline the top of the playing field:
```
printf '\n\n'
printf '%s' "     a   b   c   d   e   f   g   h   i   j"
printf '\n   %s\n' "-----------------------------------------"
```
Next, I establish a counter variable, called **r**, to keep track of how many horizontal rows have been populated. Note that, we will use the same counter variable '**r**' as our array index later in the game code. In a [Bash **for** loop][5], using the **seq** command to increment from 0 to 9, I print a digit (**d%**) to represent the row number ($row, which is defined by **seq**):
```
r=0 # our counter
for row in $(seq 0 9); do
  printf '%d  ' "$row" # print the row numbers from 0-9
```
Before we move ahead from here, lets check what we have made till now. We printed sequence **[a-j] **horizontally first and then we printed row numbers in a range **[0-9]**, we will be using these two ranges to act as our users input coordinates to locate the mine to extract.** **
Next,** **Within each row, there is a column intersection, so it's time to open a new **for** loop. This one manages each column, so it essentially generates each cell in the playing field. I have added some helper functions that you can see the full definition of in the source code. For each cell,  we need something to make the field look like a mine, so we initialize the empty ones with a dot (.), using a custom function called [**is_null_field**][6]. Also, we need an array variable to store the value for each cell, we will use the predefined global array variable **[room][7]** along with an index [variable **r**][8]. As **r** increments, we iterate over the cells, dropping mines along the way.
```
  for col in $(seq 0 9); do
    ((r+=1))  # increment the counter as we move forward in column sequence
    is_null_field $r  # assume a function which will check, if the field is empty, if so, initialize it with a dot(.)
    printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" # finally print the separator, note that, the first value of ${room[$r]} will be '.', as it is just initialized.
  #close col loop
  done
```
Finally, I keep the board well-defined by enclosing the bottom of each row with a line, and then close the row loop:
```
printf '%s\n' "|"   # print the line end separator
printf '   %s\n' "-----------------------------------------"
# close row for loop
done
printf '\n\n'
```
The full **plough** function looks like: 
```
plough()
{
  r=0
  printf '\n\n'
  printf '%s' "     a   b   c   d   e   f   g   h   i   j"
  printf '\n   %s\n' "-----------------------------------------"
  for row in $(seq 0 9); do
    printf '%d  ' "$row"
    for col in $(seq 0 9); do
       ((r+=1))
       is_null_field $r
       printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}"
    done
    printf '%s\n' "|"
    printf '   %s\n' "-----------------------------------------"
  done
  printf '\n\n'
}
```
It took me some time to decide on needing the **is_null_field**, so let's take a closer look at what it does. We need a dependable state from the beginning of the game. That choice is arbitraryit could have been a number or any character. I decided to assume everything was declared as a dot (.) because I believe it makes the gameboard look pretty. Here's what that looks like:
```
is_null_field()
{
  local e=$1 # we used index 'r' for array room already, let's call it 'e'
    if [[ -z "${room[$e]}" ]];then
      room[$r]="."  # this is where we put the dot(.) to initialize the cell/minefield
    fi
}
```
Now that, I have all the cells in our mine initialized, I get a count of all available mines by declaring and later calling a simple function shown below:
```
get_free_fields()
{
  free_fields=0    # initialize the variable
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then  # check if the cells has initial value dot(.), then count it as a free field.
      ((free_fields+=1))
    fi
  done
}
```
Here is the printed minefield, where [**a-j]** are columns, and [**0-9**] are rows.
![Minefield][9]
### Create the logic to drive the player
The player logic reads an option from [stdin][10] as a coordinate to the mines and extracts the exact field on the minefield. It uses Bash's [parameter expansion][11] to extract the column and row inputs, then feeds the column to a switch that points to its equivalent integer notation on the board, to understand this, see the values getting assigned to variable '**o'** in the switch case statement below. For instance, a player might enter **c3**, which Bash splits into two characters: **c** and **3**. For simplicity, I'm skipping over how invalid entry is handled.
```
  colm=${opt:0:1}  # get the first char, the alphabet
  ro=${opt:1:1}    # get the second char, the digit
  case $colm in
    a ) o=1;;      # finally, convert the alphabet to its equivalent integer notation.
    b ) o=2;;
    c ) o=3;;
    d ) o=4;;
    e ) o=5;;
    f ) o=6;;
    g ) o=7;;
    h ) o=8;;
    i ) o=9;;
    j ) o=10;;
  esac
```
Then it calculates the exact index and assigns the index of the input coordinates to that field.
There is also a lot of use of **shuf** command here, **shuf** is a [Linux utility][12] designed to provide a random permutation of information where the **-i** option denotes indexes or possible ranges to shuffle and **-n** denotes the maximum number or output given back. Double parentheses allow for [mathematical evaluation][13] in Bash, and we will use them heavily here.
Let's assume our previous example received **c3** via stdin. Then, **ro=3** and **o=3** from above switch case statement converted **c** to its equivalent integer, put it into our formula to calculate final index '**i'.**
```
  i=$(((ro*10)+o))   # Follow BODMAS rule, to calculate final index.
  is_free_field $i $(shuf -i 0-5 -n 1)   # call a custom function that checks if the final index value points to a an empty/free cell/field.
```
Walking through this math to understand how the final index '**i**' is calculated:
```
i=$(((ro*10)+o))
i=$(((3*10)+3))=$((30+3))=33
```
The final index value is 33. On our board, printed above, the final index points to 33rd cell and that should be 3rd (starting from 0, otherwise 4th) row and 3rd (C) column.
### Create the logic to determine the available minefield
To extract a mine, after the coordinates are decoded and the index is found, the program checks whether that field is available. If it's not, the program displays a warning, and the player chooses another coordinate.
In this code, a cell is available if it contains a dot (**.**) character. Assuming it's available, the value in the cell is reset and the score is updated. If a cell is unavailable because it does not contain a dot, then a variable **not_allowed** is set. For brevity, I leave it to you to look at the source code of the game for the contents of [the warning statement][14] in the game logic.
```
is_free_field()
{
  local f=$1
  local val=$2
  not_allowed=0
  if [[ "${room[$f]}" = "." ]]; then
    room[$f]=$val
    score=$((score+val))
  else
    not_allowed=1
  fi
}
```
![Extracting mines][15]
If the coordinate entered is available, the mine is discovered, as shown below. When **h6** is provided as input, some values at random populated on our minefields, these values are added to users score after the mins are extracted. 
![Extracting mines][16]
Now remember the variables we declared at the start, [a-g], I will now use them here to extract random mines assigning their value to the variable **m** using Bash indirection. So, depending upon the input coordinates, the program picks a random set of additional numbers (**m**) to calculate the additional fields to be populated (as shown above) by adding them to the original input coordinates, represented here by **i (**calculated above**)**.
Please note the character **X** in below code snippet, is our sole GAME-OVER trigger, we added it to our shuffle list to appear at random, with the beauty of **shuf** command, it can appear after any number of chances or may not even appear for our lucky winning user.
```
m=$(shuf -e a b c d e f g X -n 1)   # add an extra char X to the shuffle, when m=X, its GAMEOVER
  if [[ "$m" != "X" ]]; then        # X will be our explosive mine(GAME-OVER) trigger
    for limit in ${!m}; do          # !m represents the value of value of m
      field=$(shuf -i 0-5 -n 1)     # again get a random number and
      index=$((i+limit))            # add values of m to our index and calculate a new index till m reaches its last element.
      is_free_field $index $field
    done
```
I want all revealed cells to be contiguous to the cell selected by the player.
![Extracting mines][17]
### Keep a count of available and extracted mines
The program needs to keep track of available cells in the minefield; otherwise, it keeps asking the player for input even after all the cells have been revealed. To implement this, I create a variable called **free_fields**, initially setting it to 0. In a **for** loop defined by the remaining number of available cells/fields in our minefields. ****If a cell contains a dot (**.**), then the count of **free_fields** is incremented.
```
get_free_fields()
{
  free_fields=0
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then
      ((free_fields+=1))
    fi
  done
}
```
Wait, what if, the **free_fields=0**? That means, our user had extracted all the mines. Please feel free to look at [the exact code][18] to understand better.
```
if [[ $free_fields -eq 0 ]]; then   # well that means you extracted all the mines.
      printf '\n\n\t%s: %s %d\n\n' "You Win" "you scored" "$score"
      exit 0
fi
```
### Create the logic for Gameover
For the Gameover situation, we print to the middle of the terminal using some [nifty logic][19] that I leave it to the reader to explore how it works.
```
if [[ "$m" = "X" ]]; then
    g=0                      # to use it in parameter expansion
    room[$i]=X               # override the index and print X
    for j in {42..49}; do    # in the middle of the minefields,
      out="gameover"
      k=${out:$g:1}          # print one alphabet in each cell
      room[$j]=${k^^}
      ((g+=1))
    done
fi
```
 Finally, we can print the two lines which are most awaited.
```
if [[ "$m" = "X" ]]; then
      printf '\n\n\t%s: %s %d\n' "GAMEOVER" "you scored" "$score"
      printf '\n\n\t%s\n\n' "You were just $free_fields mines away."
      exit 0
fi
```
![Minecraft Gameover][20]
That's it, folks! If you want to know more, access the source code for this Minesweeper game and other games in Bash from my [GitHub repo][3]. I hope it gives you some inspiration to learn more Bash and to have fun while doing so.
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/9/advanced-bash-building-minesweeper
作者:[Abhishek Tamrakar][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/tamrakarhttps://opensource.com/users/dnearyhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/marcobravo
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bash_command_line.png?itok=k4z94W2U (bash logo on green background)
[2]: https://en.wikipedia.org/wiki/Minesweeper_(video_game)
[3]: https://github.com/abhiTamrakar/playground/tree/master/bash_games
[4]: https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays
[5]: https://opensource.com/article/19/6/how-write-loop-bash
[6]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L114-L120
[7]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L41
[8]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L74
[9]: https://opensource.com/sites/default/files/uploads/minefield.png (Minefield)
[10]: https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)
[11]: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
[12]: https://linux.die.net/man/1/shuf
[13]: https://www.tldp.org/LDP/abs/html/dblparens.html
[14]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L143-L177
[15]: https://opensource.com/sites/default/files/uploads/extractmines.png (Extracting mines)
[16]: https://opensource.com/sites/default/files/uploads/extractmines2.png (Extracting mines)
[17]: https://opensource.com/sites/default/files/uploads/extractmines3.png (Extracting mines)
[18]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L91
[19]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L131-L141
[20]: https://opensource.com/sites/default/files/uploads/gameover.png (Minecraft Gameover)

View File

@ -0,0 +1,335 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (How to Run the Top Command in Batch Mode)
[#]: via: (https://www.2daygeek.com/linux-run-execute-top-command-in-batch-mode/)
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
How to Run the Top Command in Batch Mode
======
The **[Linux Top command][1]** is the best and most well known command that everyone uses to **[monitor Linux system performance][2]**.
You probably already know most of the options available, except for a few options, and if Im not wrong, “batch more” is one of the options.
Most script writer and developers know this because this option is mainly used when writing the script.
If youre not sure about this, dont worry were here to explain this.
### What is “Batch Mode” in the Top Command
The “Batch Mode” option allows you to send top command output to other programs or to a file.
In this mode, top will not accept input and runs until the iterations limit youve set with the “-n” command-line option.
If you want to fix any performance issues on the Linux server, you need to **[understand the top command output][3]** correctly.
### 1) How to Run the Top Command in Batch Mode
By default, the top command sort the results based on CPU usage, so when you run the below top command in batch mode, it does the same and prints the first 35 lines.
```
# top -bc | head -35
top - 06:41:14 up 8 days, 20:24, 1 user, load average: 0.87, 0.77, 0.81
Tasks: 139 total, 1 running, 136 sleeping, 0 stopped, 2 zombie
%Cpu(s): 0.0 us, 3.2 sy, 0.0 ni, 96.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3880940 total, 1595932 free, 886736 used, 1398272 buff/cache
KiB Swap: 1048572 total, 514640 free, 533932 used. 2648472 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 191144 2800 1596 S 0.0 0.1 5:43.63 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
2 root 20 0 0 0 0 S 0.0 0.0 0:00.32 [kthreadd]
3 root 20 0 0 0 0 S 0.0 0.0 0:28.10 [ksoftirqd/0]
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kworker/0:0H]
7 root rt 0 0 0 0 S 0.0 0.0 0:33.96 [migration/0]
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 [rcu_bh]
9 root 20 0 0 0 0 S 0.0 0.0 63:05.12 [rcu_sched]
10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [lru-add-drain]
11 root rt 0 0 0 0 S 0.0 0.0 0:08.79 [watchdog/0]
12 root rt 0 0 0 0 S 0.0 0.0 0:08.82 [watchdog/1]
13 root rt 0 0 0 0 S 0.0 0.0 0:44.27 [migration/1]
14 root 20 0 0 0 0 S 0.0 0.0 1:22.45 [ksoftirqd/1]
16 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kworker/1:0H]
18 root 20 0 0 0 0 S 0.0 0.0 0:00.01 [kdevtmpfs]
19 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [netns]
20 root 20 0 0 0 0 S 0.0 0.0 0:01.35 [khungtaskd]
21 root 0 -20 0 0 0 S 0.0 0.0 0:00.02 [writeback]
22 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kintegrityd]
23 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [bioset]
24 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kblockd]
25 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [md]
26 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [edac-poller]
33 root 20 0 0 0 0 S 0.0 0.0 1:19.07 [kswapd0]
34 root 25 5 0 0 0 S 0.0 0.0 0:00.00 [ksmd]
35 root 39 19 0 0 0 S 0.0 0.0 0:12.80 [khugepaged]
36 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [crypto]
44 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kthrotld]
46 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kmpath_rdacd]
```
### 2) How to Run the Top Command in Batch Mode and Sort the Output Based on Memory Usage
Run the below top command to sort the results based on memory usage in batch mode.
```
# top -bc -o +%MEM | head -n 20
top - 06:42:00 up 8 days, 20:25, 1 user, load average: 0.66, 0.74, 0.80
Tasks: 146 total, 1 running, 145 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3880940 total, 1422044 free, 1059176 used, 1399720 buff/cache
KiB Swap: 1048572 total, 514640 free, 533932 used. 2475984 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18105 mysql 20 0 1453900 156096 8816 S 0.0 4.0 2:12.98 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
1841 root 20 0 228980 107036 5360 S 0.0 2.8 0:05.56 /usr/local/cpanel/3rdparty/perl/528/bin/perl -T -w /usr/local/cpanel/3rdparty/bin/spamd --max-children=3 --max-spare=1 --allowed-ips=127.0.0.+
4301 root 20 0 230208 104608 1816 S 0.0 2.7 0:03.77 spamd child
8139 nobody 20 0 257000 27108 3408 S 0.0 0.7 0:00.04 /usr/sbin/httpd -k start
7961 nobody 20 0 256988 26912 3160 S 0.0 0.7 0:00.05 /usr/sbin/httpd -k start
8190 nobody 20 0 256976 26812 3140 S 0.0 0.7 0:00.05 /usr/sbin/httpd -k start
8353 nobody 20 0 256976 26812 3144 S 0.0 0.7 0:00.04 /usr/sbin/httpd -k start
8629 nobody 20 0 256856 26736 3108 S 0.0 0.7 0:00.02 /usr/sbin/httpd -k start
8636 nobody 20 0 256856 26712 3100 S 0.0 0.7 0:00.03 /usr/sbin/httpd -k start
8611 nobody 20 0 256844 25764 2228 S 0.0 0.7 0:00.01 /usr/sbin/httpd -k start
8451 nobody 20 0 256844 25760 2220 S 0.0 0.7 0:00.04 /usr/sbin/httpd -k start
8610 nobody 20 0 256844 25748 2224 S 0.0 0.7 0:00.01 /usr/sbin/httpd -k start
8632 nobody 20 0 256844 25744 2216 S 0.0 0.7 0:00.03 /usr/sbin/httpd -k start
```
**Details of the above command:**
* **-b :** Batch mode operation
* **-c :** To print the absolute path of the running process
* **-o :** To specify fields for sorting processes
* **head :** Output the first part of files
* **-n :** To print the first “n” lines
### 3) How to Run the Top Command in Batch Mode and Sort the Output Based on a Specific User Process
If you want to sort results based on a specific user, run the below top command.
```
# top -bc -u mysql | head -n 10
top - 06:44:58 up 8 days, 20:27, 1 user, load average: 0.99, 0.87, 0.84
Tasks: 140 total, 1 running, 137 sleeping, 0 stopped, 2 zombie
%Cpu(s): 13.3 us, 3.3 sy, 0.0 ni, 83.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3880940 total, 1589832 free, 885648 used, 1405460 buff/cache
KiB Swap: 1048572 total, 514640 free, 533932 used. 2649412 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18105 mysql 20 0 1453900 156888 8816 S 0.0 4.0 2:16.42 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
```
### 4) How to Run the Top Command in Batch Mode and Sort the Output Based on the Process Age
Use the below top command to sort the results based on the age of the process in batch mode. It shows the total CPU time the task has used since it started.
But if you want to check how long a process has been running on Linux, go to the following article.
* **[Five Ways to Check How Long a Process Has Been Running in Linux][4]**
```
# top -bc -o TIME+ | head -n 20
top - 06:45:56 up 8 days, 20:28, 1 user, load average: 0.56, 0.77, 0.81
Tasks: 148 total, 1 running, 146 sleeping, 0 stopped, 1 zombie
%Cpu(s): 0.0 us, 3.1 sy, 0.0 ni, 96.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3880940 total, 1378664 free, 1094876 used, 1407400 buff/cache
KiB Swap: 1048572 total, 514640 free, 533932 used. 2440332 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9 root 20 0 0 0 0 S 0.0 0.0 63:05.70 [rcu_sched]
272 root 20 0 0 0 0 S 0.0 0.0 16:12.13 [xfsaild/vda1]
3882 root 20 0 229832 6212 1220 S 0.0 0.2 9:00.84 /usr/sbin/httpd -k start
1 root 20 0 191144 2800 1596 S 0.0 0.1 5:43.75 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
3761 root 20 0 68784 9820 2048 S 0.0 0.3 5:09.67 tailwatchd
3529 root 20 0 404380 3472 2604 S 0.0 0.1 3:24.98 /usr/sbin/rsyslogd -n
3520 root 20 0 574208 572 164 S 0.0 0.0 3:07.74 /usr/bin/python2 -Es /usr/sbin/tuned -l -P
444 dbus 20 0 58444 1144 612 S 0.0 0.0 2:23.90 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
18105 mysql 20 0 1453900 157152 8816 S 0.0 4.0 2:17.29 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
249 root 0 -20 0 0 0 S 0.0 0.0 1:28.83 [kworker/0:1H]
14 root 20 0 0 0 0 S 0.0 0.0 1:22.46 [ksoftirqd/1]
33 root 20 0 0 0 0 S 0.0 0.0 1:19.07 [kswapd0]
342 root 20 0 39472 2940 2752 S 0.0 0.1 1:18.17 /usr/lib/systemd/systemd-journald
```
### 5) How to Run the Top Command in Batch Mode and Save the Output to a File
If you want to share the output of the top command to someone for troubleshooting purposes, redirect the output to a file using the following command.
```
# top -bc | head -35 > top-report.txt
# cat top-report.txt
top - 06:47:11 up 8 days, 20:30, 1 user, load average: 0.67, 0.77, 0.81
Tasks: 133 total, 4 running, 129 sleeping, 0 stopped, 0 zombie
%Cpu(s): 59.4 us, 12.5 sy, 0.0 ni, 28.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3880940 total, 1596268 free, 843284 used, 1441388 buff/cache
KiB Swap: 1048572 total, 514640 free, 533932 used. 2659084 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9686 daygeekc 20 0 406132 62184 43448 R 94.1 1.6 0:00.34 /opt/cpanel/ea-php56/root/usr/bin/php-cgi
9689 nobody 20 0 256588 24428 1184 S 5.9 0.6 0:00.01 /usr/sbin/httpd -k start
1 root 20 0 191144 2800 1596 S 0.0 0.1 5:43.79 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
2 root 20 0 0 0 0 S 0.0 0.0 0:00.32 [kthreadd]
3 root 20 0 0 0 0 S 0.0 0.0 0:28.11 [ksoftirqd/0]
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kworker/0:0H]
7 root rt 0 0 0 0 S 0.0 0.0 0:33.96 [migration/0]
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 [rcu_bh]
9 root 20 0 0 0 0 R 0.0 0.0 63:05.82 [rcu_sched]
10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [lru-add-drain]
11 root rt 0 0 0 0 S 0.0 0.0 0:08.79 [watchdog/0]
12 root rt 0 0 0 0 S 0.0 0.0 0:08.82 [watchdog/1]
13 root rt 0 0 0 0 S 0.0 0.0 0:44.28 [migration/1]
14 root 20 0 0 0 0 S 0.0 0.0 1:22.46 [ksoftirqd/1]
16 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kworker/1:0H]
18 root 20 0 0 0 0 S 0.0 0.0 0:00.01 [kdevtmpfs]
19 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [netns]
20 root 20 0 0 0 0 S 0.0 0.0 0:01.35 [khungtaskd]
21 root 0 -20 0 0 0 S 0.0 0.0 0:00.02 [writeback]
22 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kintegrityd]
23 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [bioset]
24 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kblockd]
25 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [md]
26 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [edac-poller]
33 root 20 0 0 0 0 S 0.0 0.0 1:19.07 [kswapd0]
34 root 25 5 0 0 0 S 0.0 0.0 0:00.00 [ksmd]
35 root 39 19 0 0 0 S 0.0 0.0 0:12.80 [khugepaged]
36 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [crypto]
```
### How to Sort Output Based on Specific Fields
In the latest version of the top command release, press the **“f”** key to sort the fields via the field letter.
To sort with a new field, use the **“up/down”** arrow to select the correct selection, and then press **“s”** to sort it. Finally press **“q”** to exit from this window.
```
Fields Management for window 1:Def, whose current sort field is %CPU
Navigate with Up/Dn, Right selects for move then or Left commits,
'd' or toggles display, 's' sets sort. Use 'q' or to end!
PID = Process Id nsUTS = UTS namespace Inode
USER = Effective User Name LXC = LXC container name
PR = Priority RSan = RES Anonymous (KiB)
NI = Nice Value RSfd = RES File-based (KiB)
VIRT = Virtual Image (KiB) RSlk = RES Locked (KiB)
RES = Resident Size (KiB) RSsh = RES Shared (KiB)
SHR = Shared Memory (KiB) CGNAME = Control Group name
S = Process Status NU = Last Used NUMA node
%CPU = CPU Usage
%MEM = Memory Usage (RES)
TIME+ = CPU Time, hundredths
COMMAND = Command Name/Line
PPID = Parent Process pid
UID = Effective User Id
RUID = Real User Id
RUSER = Real User Name
SUID = Saved User Id
SUSER = Saved User Name
GID = Group Id
GROUP = Group Name
PGRP = Process Group Id
TTY = Controlling Tty
TPGID = Tty Process Grp Id
SID = Session Id
nTH = Number of Threads
P = Last Used Cpu (SMP)
TIME = CPU Time
SWAP = Swapped Size (KiB)
CODE = Code Size (KiB)
DATA = Data+Stack (KiB)
nMaj = Major Page Faults
nMin = Minor Page Faults
nDRT = Dirty Pages Count
WCHAN = Sleeping in Function
Flags = Task Flags
CGROUPS = Control Groups
SUPGIDS = Supp Groups IDs
SUPGRPS = Supp Groups Names
TGID = Thread Group Id
OOMa = OOMEM Adjustment
OOMs = OOMEM Score current
ENVIRON = Environment vars
vMj = Major Faults delta
vMn = Minor Faults delta
USED = Res+Swap Size (KiB)
nsIPC = IPC namespace Inode
nsMNT = MNT namespace Inode
nsNET = NET namespace Inode
nsPID = PID namespace Inode
nsUSER = USER namespace Inode
```
For older version of the top command, press the **“shift+f”** or **“shift+o”** key to sort the fields via the field letter.
To sort with a new field, select the corresponding sort **field letter**, and then press **“Enter”** to sort it.
```
Current Sort Field: N for window 1:Def
Select sort field via field letter, type any other key to return
a: PID = Process Id
b: PPID = Parent Process Pid
c: RUSER = Real user name
d: UID = User Id
e: USER = User Name
f: GROUP = Group Name
g: TTY = Controlling Tty
h: PR = Priority
i: NI = Nice value
j: P = Last used cpu (SMP)
k: %CPU = CPU usage
l: TIME = CPU Time
m: TIME+ = CPU Time, hundredths
* N: %MEM = Memory usage (RES)
o: VIRT = Virtual Image (kb)
p: SWAP = Swapped size (kb)
q: RES = Resident size (kb)
r: CODE = Code size (kb)
s: DATA = Data+Stack size (kb)
t: SHR = Shared Mem size (kb)
u: nFLT = Page Fault count
v: nDRT = Dirty Pages count
w: S = Process Status
x: COMMAND = Command name/line
y: WCHAN = Sleeping in Function
z: Flags = Task Flags
Note1:
If a selected sort field can't be
shown due to screen width or your
field order, the '<' and '>' keys
will be unavailable until a field
within viewable range is chosen.
Note2:
Field sorting uses internal values,
not those in column display. Thus,
the TTY & WCHAN fields will violate
strict ASCII collating sequence.
(shame on you if WCHAN is chosen)
```
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/linux-run-execute-top-command-in-batch-mode/
作者:[Magesh Maruthamuthu][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.2daygeek.com/author/magesh/
[b]: https://github.com/lujun9972
[1]: https://www.2daygeek.com/linux-top-command-linux-system-performance-monitoring-tool/
[2]: https://www.2daygeek.com/category/system-monitoring/
[3]: https://www.2daygeek.com/understanding-linux-top-command-output-usage/
[4]: https://www.2daygeek.com/how-to-check-how-long-a-process-has-been-running-in-linux/

View File

@ -0,0 +1,334 @@
[#]: collector: (lujun9972)
[#]: translator: (wenwensnow)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Hone advanced Bash skills by building Minesweeper)
[#]: via: (https://opensource.com/article/19/9/advanced-bash-building-minesweeper)
[#]: author: (Abhishek Tamrakar https://opensource.com/users/tamrakarhttps://opensource.com/users/dnearyhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/marcobravo)
通过编写扫雷游戏提高你的bash技巧
======
那些令人怀念的经典游戏可是提高编程能力的好素材。今天就让我们仔细探索一番怎么用Bash编写一个扫雷程序。
![bash logo on green background][1]
我在编程教学方面不是专家但当我想更好掌握某一样东西时会试着找出让自己乐在其中的方法。比方说当我想在shell编程方面更进一步时我决定用Bash编写一个[扫雷][2]游戏来加以练习。
如果你是一个有经验的Bash程序员并且在提高技巧的同时乐在其中你可以在终端中编写个人版本的扫雷。完整代码可以在这个 [GitHub 库]中找到[3].
### 做好准备
在我编写任何代码之前,我列出了游戏所必须的几个部分:
1. 显示雷区
2. 创建玩家逻辑
3. 创建判断单元格是否可选的逻辑
4. 记录已选择和可用单元格的个数
5. 创建游戏结束逻辑
### 显示雷区
在扫雷中游戏界面是一个由2D数组列和行组成的不透明小方格。每一格下都有可能藏有地雷。玩家的任务就是找到那些不含雷的方格并且在这一过程中不能点到地雷。Bash版本的扫雷使用10x10的矩阵实际逻辑则由一个简单的Bash数组来完成。
首先,我先生成了一些随机数字。这将是地雷在雷区里的位置。为了控制地雷的数量,在开始编写代码之前,这么做会容易一些。实现这一功能的逻辑可以更好,但我这么做,是为了让游戏实现保持简洁,并有改进空间。(我编写这个游戏纯属娱乐,但如果你能将它修改的更好,我也是很乐意的。)
下面这些变量是整个过程中是不变的声明它们是为了随机生成数字。就像下面的变量a-g它们会被用来计算可选择的地雷
的值:
```
# 变量
score=0 # 会用来存放游戏分数
#下面这些变量,用来随机生成可选择地雷的实际值
a="1 10 -10 -1"
b="-1 0 1"
c="0 1"
d="-1 0 1 -2 -3"
e="1 2 20 21 10 0 -10 -20 -23 -2 -1"
f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 -3 -2 -1"
g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7"
#
# 声明
declare -a room # 声明一个room 数组,它用来表示雷区的每一格。
```
接下来我会用列0-9和行a-j显示出游戏界面,并且使用一个10x10矩阵作为雷区。M[10][10] 是一个索引从0-99有100个值的数组。 如想了解更多关于Bash 数组的内容,请阅读这本书[_那些关于Bash你所不了解的事: Bash数组简介_][4]。
创建一个叫 **plough**的函数,我们先将标题显示出来:两个空行,列头,和一行 “-”,以示意往下是游戏界面:
```
printf '\n\n'
printf '%s' "     a   b   c   d   e   f   g   h   i   j"
printf '\n   %s\n' "-----------------------------------------"
```
然后,我初始化一个计数器变量,叫 **r**,它会用来记录已显示多少横行。 注意,稍后在游戏代码中,我们会用同一个变量**r**,作为我们的数组索引。 在 [Bash **for** 循环][5]中,用 **seq**命令从0增加到9。我用 (**d%**)占位,来显示行号($row,被**seq**定义的变量)
```
r=0 # our counter
for row in $(seq 0 9); do
printf '%d ' "$row" # 显示 行数 0-9
```
在我们接着往下做之前,让我们看看到现在都做了什么。我们先横着显示 **[a-j]** 然后再将 **[0-9]** 的行号显示出来,我们会用这两个范围,来确定用户选择的确切位置。
接着,在每行中,插入列,所以是时候写一个新的 **for** 循环了。 这一循环管理着每一列,也就是说,实际上是生成游戏界面的每一格。我添加了一些说明函数,你能在源码中看到它的完整实现。 对每一格来说,我们需要一些让它看起来像地雷的东西,所以我们先用一个点(.)来初始化空格。实现这一想法,我们用的是一个叫[**is_null_field**][6] 的自定义函数。 同时,我们需要一个存储每一格具体值的数组,这儿会用到之前已定义的全局数组 **[room][7]** , 并用 [变量 **r**][8]作为索引。 随着 **r** 的增加,遍历所有单元格,并随机部署地雷。
```
  for col in $(seq 0 9); do
((r+=1)) # 循环完一列行数加一
is_null_field $r # 假设这里有个函数,它会检查单元格是否为空,为真,则此单元格初始值为点(.
printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" # 最后显示分隔符,注意,${room[$r]} 的第一个值为 '.',等于其初始值。
#结束 col 循环
done
```
最后,为了保持游戏界面整齐好看,我会在每行用一个竖线作为结尾,并在最后结束行循环:
```
printf '%s\n' "|" #显示出行分隔符
printf ' %s\n' "-----------------------------------------"
# 结束行循环
done
printf '\n\n'
```
完整的 **plough** 代码如下:
```
plough()
{
  r=0
  printf '\n\n'
  printf '%s' "     a   b   c   d   e   f   g   h   i   j"
  printf '\n   %s\n' "-----------------------------------------"
  for row in $(seq 0 9); do
    printf '%d  ' "$row"
    for col in $(seq 0 9); do
       ((r+=1))
       is_null_field $r
       printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}"
    done
    printf '%s\n' "|"
    printf '   %s\n' "-----------------------------------------"
  done
  printf '\n\n'
}
```
我花了点时间来思考,**is_null_field** 的具体功能是什么。让我们来看看,它到底能做些什么。在最开始,我们需要游戏有一个固定的状态。你可以随便选择所有格子的初始值,可以是一个数字或者任意字符。 我最后决定,所有单元格的初始值为一个点(.),因为我觉得,这样会让游戏界面更好看。下面就是这一函数的完整代码:
```
is_null_field()
{
local e=$1 # 在数组room中我们已经用过循环变量 'r'了,这次我们用'e'
if [[ -z "${room[$e]}" ]];then
room[$r]="." #这里用点.)来初始化每一个单元格
fi
}
```
现在,我已经初始化了所有的格子,现在只要用一个很简单的函数,就能得出,当前游戏中还有多少单元格可以操作:
```
get_free_fields()
{
free_fields=0 # 初始化变量
for n in $(seq 1 ${#room[@]}); do
if [[ "${room[$n]}" = "." ]]; then # 检查当前单元格是否等于初始值(.),结果为真,则记为空余格子。
((free_fields+=1))
    fi
  done
}
```
这是显示出来的游戏界面,[**a-j]** 为列, [**0-9**] 为行。
![Minefield][9]
### 创建玩家逻辑
玩家操作背后的逻辑在于,先从[stdin][10] 中读取数据作为坐标然后再找出对应位置实际包含的值。这里用到了Bash的[参数扩展][11]来设法得到行列数。然后将代表列数的字母传给switch,从而得到其对应的列数。为了更好地理解这一过程,可以看看下面这段代码中,变量 '**o'** 所对应的值。 举个例子,玩家输入了 **c3** ,这时 Bash 将其分成两个字符: **c** and **3** 。 为了简单起见,我跳过了如何处理无效输入的部分。
```
colm=${opt:0:1} # 得到第一个字符,一个字母
ro=${opt:1:1} # 得到第二个字符,一个整数
case $colm in
a ) o=1;; # 最后,通过字母得到对应列数。
b ) o=2;;
    c ) o=3;;
    d ) o=4;;
    e ) o=5;;
    f ) o=6;;
    g ) o=7;;
    h ) o=8;;
    i ) o=9;;
    j ) o=10;;
  esac
```
下面的代码会计算,用户所选单元格实际对应的数字,然后将结果储存在变量中。
这里也用到了很多的 **shuf** 命令,**shuf** 是一个专门用来生成随机序列的[Linux命令][12]。 **-i** 选项,后面需要提供需要打乱的数或者范围, **-n** 选择则规定输出结果最多需要返回几个值。Bash中可以在两个圆括号内进行[数学计算],这里我们会多次用到。
还是沿用之前的例子,玩家输入了 **c3** 。 接着,它被转化成了**ro=3** 和 **o=3**。 之后通过上面的switch 代码, 将**c** 转化为对应的整数,带进公式,以得到最终结果 '**i'.** 的值。
```
i=$(((ro*10)+o)) # 遵循运算规则,算出最终值
is_free_field $i $(shuf -i 0-5 -n 1) # 调用自定义函数,判断其指向空/可选择单元格。
```
仔细观察这个计算过程,看看最终结果 '**i**' 是如何计算出来的:
```
i=$(((ro*10)+o))
i=$(((3*10)+3))=$((30+3))=33
```
最后结果是33。在我们的游戏界面显示出来玩家输入坐标指向了第33个单元格也就是在第3行从0开始否则这里变成4第3列。
### 创建判断单元格是否可选的逻辑
为了找到地雷,在将坐标转化,并找到实际位置之后,程序会检查这一单元格是否可选。如不可选,程序会显示一条警告信息,并要求玩家重新输入坐标。
在这段代码中,单元格是否可选,是由数组里对应的值是否为点(**.**)决定的。 如果可选,则重置单元格对应的值,并更新分数。反之,因为其对应值不为点,则设置 变量 **not_allowed**。 为简单起见,游戏中[警告消息][14]这部分源码,我会留给读者们自己去探索。
```
is_free_field()
{
  local f=$1
  local val=$2
  not_allowed=0
  if [[ "${room[$f]}" = "." ]]; then
    room[$f]=$val
    score=$((score+val))
  else
    not_allowed=1
  fi
}
```
![Extracting mines][15]
如输入坐标有效,且对应位置为地雷,如下图所示。 玩家输入 **h6**,游戏界面会出现一些随机生成的值。在发现地雷后,这些值会被加入用户得分。
![Extracting mines][16]
还记得我们开头定义的变量,[a-g]吗,我会用它们来确定,随机生成地雷的具体值。 所以,根据玩家输入坐标,程序会根据 (**m**) 中随机生成的数,来生成周围其他单元格的值。(如上图所示) 。之后将所有值和初始输入坐标相加,最后结果放在**i (**计算结果如上**)**中.
请注意下面代码中的 **X**,它是我们唯一的游戏结束标志。我们将它添加到随机列表中。在 **shuf** 命令的魔力下X可以在任意情况下出现但如果你足够幸运的话也可能一直不会出现。
```
m=$(shuf -e a b c d e f g X -n 1) # 将 X 添加到随机列表中,当 m=X,游戏结束
if [[ "$m" != "X" ]]; then # X将会是我们爆炸地雷游戏结束的触发标志
for limit in ${!m}; do # !m 代表m变量的值
field=$(shuf -i 0-5 -n 1) # 然后再次获得一个随机数字
index=$((i+limit)) # 将m中的每一个值和index加起来直到列表结尾
is_free_field $index $field
    done
```
我想要游戏界面中,所有随机显示出来的单元格,都靠近玩家选择的单元格。
![Extracting mines][17]
### 记录已选择和可用单元格的个数
这个程序需要记录,游戏界面中哪些单元格是可选择的。否则,程序会一直让用户输入数据,即使所有单元格都被选中过。为了实现这一功能,我创建了一个叫 **free_fields** 的变量初始值为0。 用一个 **for** 循环,记录下游戏界面中可选择单元格的数量。 ****如果单元格所对应的值为点 (**.**), 则 **free_fields** 加一。
```
get_free_fields()
{
  free_fields=0
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then
      ((free_fields+=1))
    fi
  done
}
```
等下,如果 **free_fields=0** 呢? 这意味着,玩家已选择过所有单元格。如果想更好理解这一部分,可以看看这里的[源代码][18] 。
```
if [[ $free_fields -eq 0 ]]; then # 这意味着你已选择过所有格子
printf '\n\n\t%s: %s %d\n\n' "You Win" "you scored" "$score"
      exit 0
fi
```
### 创建游戏结束逻辑
对于游戏结束这种情况,我们这里使用了一些很巧妙的技巧,将结果在屏幕中央显示出来。我把这部分留给读者朋友们自己去探索。
```
if [[ "$m" = "X" ]]; then
g=0 # 为了在参数扩展中使用它
room[$i]=X # 覆盖此位置原有的值并将其赋值为X
for j in {42..49}; do # 在游戏界面中央,
out="gameover"
k=${out:$g:1} # 在每一格中显示一个字母
room[$j]=${k^^}
      ((g+=1))
    done
fi
```
最后,我们显示出玩家最关心的两行。
```
if [[ "$m" = "X" ]]; then
      printf '\n\n\t%s: %s %d\n' "GAMEOVER" "you scored" "$score"
      printf '\n\n\t%s\n\n' "You were just $free_fields mines away."
      exit 0
fi
```
![Minecraft Gameover][20]
文章到这里就结束了,朋友们! 如果你想了解更多,具体可以查看我的[GitHub 库][3]那儿有这个扫雷游戏的源代码并且你还能找到更多用Bash 编写的游戏。 我希望这篇文章能激起你学习Bash的兴趣并乐在其中。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/9/advanced-bash-building-minesweeper
作者:[Abhishek Tamrakar][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/tamrakarhttps://opensource.com/users/dnearyhttps://opensource.com/users/sethhttps://opensource.com/users/sethhttps://opensource.com/users/marcobravo
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bash_command_line.png?itok=k4z94W2U (bash logo on green background)
[2]: https://en.wikipedia.org/wiki/Minesweeper_(video_game)
[3]: https://github.com/abhiTamrakar/playground/tree/master/bash_games
[4]: https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays
[5]: https://opensource.com/article/19/6/how-write-loop-bash
[6]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L114-L120
[7]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L41
[8]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L74
[9]: https://opensource.com/sites/default/files/uploads/minefield.png (Minefield)
[10]: https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)
[11]: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
[12]: https://linux.die.net/man/1/shuf
[13]: https://www.tldp.org/LDP/abs/html/dblparens.html
[14]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L143-L177
[15]: https://opensource.com/sites/default/files/uploads/extractmines.png (Extracting mines)
[16]: https://opensource.com/sites/default/files/uploads/extractmines2.png (Extracting mines)
[17]: https://opensource.com/sites/default/files/uploads/extractmines3.png (Extracting mines)
[18]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L91
[19]: https://github.com/abhiTamrakar/playground/blob/28143053ced699c80569666f25268e8b96c38c46/bash_games/minesweeper.sh#L131-L141
[20]: https://opensource.com/sites/default/files/uploads/gameover.png (Minecraft Gameover)