mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-04 22:00:34 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
4e7af3ada5
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11547-1.html)
|
||||
[#]: subject: (Viewing network bandwidth usage with bmon)
|
||||
[#]: via: (https://www.networkworld.com/article/3447936/viewing-network-bandwidth-usage-with-bmon.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
@ -0,0 +1,130 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Getting started with Pimcore: An open source alternative for product information management)
|
||||
[#]: via: (https://opensource.com/article/19/11/pimcore-alternative-product-information-management)
|
||||
[#]: author: (Dietmar Rietsch https://opensource.com/users/erinmcmahon)
|
||||
|
||||
Getting started with Pimcore: An open source alternative for product information management
|
||||
======
|
||||
PIM software enables sellers to centralize sales, marketing, and
|
||||
technical product information to engage better with customers.
|
||||
![Pair programming][1]
|
||||
|
||||
Product information management (PIM) software enables sellers to consolidate product data into a centralized repository that acts as a single source of truth, minimizing errors and redundancies in product data. This, in turn, makes it easier to share high-quality, clear, and accurate product information across customer touchpoints, paving the way for rich, consistent, readily accessible content that's optimized for all the channels customers use, including websites, social platforms, marketplaces, apps, IoT devices, conversational interfaces, and even print catalogs and physical stores. Being able to engage with customers on their favorite platform is essential for increasing sales and expanding into new markets. For years, there have been proprietary products that address some of these needs, like Salsify for data management, Adobe Experience Manager, and SAP Commerce Cloud for experience management, but now there's an open source alternative called Pimcore.
|
||||
|
||||
[Pimcore PIM][2] is an open source enterprise PIM, dual-[licensed][3] under GPLv3 and Pimcore Enterprise License (PEL) that enables sellers to centralize and harmonize sales, marketing, and technical product information. Pimcore can acquire, manage, and share any digital data and integrate easily into an existing IT system landscape. Its API-driven, service-oriented architecture enables fast and seamless connection to third-party software such as enterprise resource planning (ERP), customer relationship management (CRM), business intelligence (BI), and more.
|
||||
|
||||
### Open source vs. proprietary PIM software
|
||||
|
||||
There are at least four significant differences between open source and proprietary software that PIM users should consider.
|
||||
|
||||
* **Vendor lock-in:** It is more difficult to customize proprietary software. If you want to develop a new feature or modify an existing one, proprietary software lock-in makes you dependent on the vendor. On the other hand, open source provides unlimited access and flexibility to modify the source code and leverage it to your advantage, as well as the opportunity to freely access contributions made by the community behind it.
|
||||
* **Interoperability:** Open source PIM software offers greater interoperability capabilities with APIs for integration with third-party business applications. Since the source code is open and available, users can customize or build connectors to meet their needs, which is not possible with proprietary software.
|
||||
* **Community:** Open source solutions are supported by vibrant communities of contributors, implementers, developers, and other enthusiasts working towards enhancing the solution. Proprietary PIM software typically depends on commercial partnerships for implementation assistance and customizations.
|
||||
* **Total cost of ownership:** Proprietary software carries a significant license fee for deployment, which includes implementation, customization, and system maintenance. In contrast, open source software development can be done in-house or through an IT vendor. This becomes a huge advantage for enterprises with tight budgets, as it slashes PIM operating costs.
|
||||
|
||||
|
||||
|
||||
### Pimcore features
|
||||
|
||||
Pimcore's platform is divided into two core offerings: data management and experience management. In addition to being open source and free to download and use, its features include the following.
|
||||
|
||||
#### Data modeling
|
||||
|
||||
Pimcore's web-based data modeling engine has over 40 high-performance data types that can help companies easily manage zillions of products or other master data with thousands of attributes. It also offers multilingual data management, object relations, data classification, digital asset management (DAM), and data modeling supported by data inheritance.
|
||||
|
||||
![Pimcore translations inheritance][4]
|
||||
|
||||
#### Data management
|
||||
|
||||
Pimcore enables efficient enterprise data management that focuses on ease of use; consistency in aggregation, organization, classification, and translation of product information; and sound data governance to enable optimization, flexibility, and scalability.
|
||||
|
||||
![PIM batch change][5]
|
||||
|
||||
#### Data quality
|
||||
|
||||
Data quality management is the basis for analytics and business intelligence (BI). Pimcore supports data quality, completeness, and validation, and includes rich auditing and versioning features to help organizations meet revenue goals, compliance requirements, and productivity objectives. Pimcore also offers a configurable dashboard, custom reports capabilities, filtering, and export functionalities.
|
||||
|
||||
![PIM data quality and completeness][6]
|
||||
|
||||
#### Workflow management
|
||||
|
||||
Pimcore's advanced workflow engine makes it easy to build and modify workflows to improve accuracy and productivity and reduce risks. Drop-downs enable enterprises to chalk out workflow paths to define business processes and editorial workflows with ease, and the customizable management and administration interface makes it easy to integrate workflows into an organization's application infrastructure.
|
||||
|
||||
![Pimcore workflow management][7]
|
||||
|
||||
#### Data consolidation
|
||||
|
||||
Pimcore eliminates data silos by consolidating data in a central place and creating a single master data record or a single point of truth. It does this by gathering data lying in disparate systems spread across geographic locations, departments, applications, hard drives, vendors, suppliers, and more. By consolidating data, enterprises can get improved accuracy, reliability, and efficacy of information, lower cost of compliance, and decreased time-to-market.
|
||||
|
||||
#### Synchronization across channels
|
||||
|
||||
Pimcore's tools for gathering and managing digital data enable sellers to deliver it across any channel or device to reach individual customers on their preferred platforms. This helps enterprises enrich the user experience, leverage a single point of control to optimize performance, improve data governance, streamline product data lifecycle management, and boost productivity to reduce time-to-market and meet customers' expectations.
|
||||
|
||||
### Installing, trying, and using Pimcore
|
||||
|
||||
The best way to start exploring Pimcore is with a guided tour or demo; before you begin, make sure that you have the [system requirements][8] in place.
|
||||
|
||||
#### Demo Pimcore
|
||||
|
||||
Navigate to the [Pimcore demo][9] page and either register for a guided tour or click on one of the products in the "Try By Yourself" column for a self-guided demo. Enter the username **admin** and password **demo** to begin the demo.
|
||||
|
||||
![Pimcore demo page][10]
|
||||
|
||||
#### Download and install Pimcore
|
||||
|
||||
If you want to take a deeper dive, you can [download Pimcore][11]; you can choose the data management or the experience management offering or both. You will need to enter your contact information and then immediately receive installation instructions.
|
||||
|
||||
![Pimcore download interface][12]
|
||||
|
||||
You can also choose from four installation packages: three are demo packages for beginners, and one is a skeleton for experienced developers. All contain:
|
||||
|
||||
* Complete Pimcore platform
|
||||
* Latest open source version
|
||||
* Quick-start guide
|
||||
* Demo data for getting started
|
||||
|
||||
|
||||
|
||||
If you are installing Pimcore on a typical [LAMP][13] environment (which is recommended), see the [Pimcore installation guide][14]. If you're using another setup (e.g., Nginx), see the [installation, setup, and upgrade guide][15] for details.
|
||||
|
||||
![Pimcore installation documentation][16]
|
||||
|
||||
### Contribute to Pimcore
|
||||
|
||||
As open source software, users are encouraged to engage with, [contribute][17] to, and fork Pimcore. For tracking bugs and features, as well as for software management, Pimcore relies exclusively on [GitHub][18], where contributions are assessed and carefully curated to uphold Pimcore's quality standards.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/pimcore-alternative-product-information-management
|
||||
|
||||
作者:[Dietmar Rietsch][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/erinmcmahon
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/collab-team-pair-programming-code-keyboard.png?itok=kBeRTFL1 (Pair programming)
|
||||
[2]: https://pimcore.com/en
|
||||
[3]: https://github.com/pimcore/pimcore/blob/master/LICENSE.md
|
||||
[4]: https://opensource.com/sites/default/files/uploads/pimcoretranslationinheritance.png (Pimcore translations inheritance)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/pimcorebatchchange.png (PIM batch change)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/pimcoredataquality.png (PIM data quality and completeness)
|
||||
[7]: https://opensource.com/sites/default/files/pimcore-workflow-management.jpg (Pimcore workflow management)
|
||||
[8]: https://pimcore.com/docs/5.x/Development_Documentation/Installation_and_Upgrade/System_Requirements.html
|
||||
[9]: https://pimcore.com/en/try
|
||||
[10]: https://opensource.com/sites/default/files/uploads/pimcoredemopage.png (Pimcore demo page)
|
||||
[11]: https://pimcore.com/en/download
|
||||
[12]: https://opensource.com/sites/default/files/uploads/pimcoredownload.png (Pimcore download interface)
|
||||
[13]: https://en.wikipedia.org/wiki/LAMP_(software_bundle)
|
||||
[14]: https://pimcore.com/docs/5.x/Development_Documentation/Getting_Started/Installation.html
|
||||
[15]: https://pimcore.com/docs/5.x/Development_Documentation/Installation_and_Upgrade/index.html
|
||||
[16]: https://opensource.com/sites/default/files/uploads/pimcoreinstall.png (Pimcore installation documentation)
|
||||
[17]: https://github.com/pimcore/pimcore/blob/master/CONTRIBUTING.md
|
||||
[18]: https://github.com/pimcore/pimcore
|
@ -0,0 +1,78 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (What it Takes to Be a Successful Network Engineer)
|
||||
[#]: via: (https://opensourceforu.com/2019/11/what-it-takes-to-be-a-successful-network-engineer/)
|
||||
[#]: author: (Christopher Nichols https://opensourceforu.com/author/christopher-nichols/)
|
||||
|
||||
What it Takes to Be a Successful Network Engineer
|
||||
======
|
||||
|
||||
[![][1]][2]
|
||||
|
||||
_Network engineering is an excellent field filled with complex and fulfilling work, and many job opportunities. As companies end up with networks that continue to become more complex and connect more devices together, network engineers are in high-demand. Being successful in this role requires several characteristics and skill sets that serve employees well in this fast-paced and mission-critical environment._
|
||||
|
||||
**Deep Understanding of Networking Technologies**
|
||||
Some people might think that this characteristic is assumed when it comes to network engineering. However, there’s a distinct difference between knowing enough about networking to manage and monitor the system, and having a truly in-depth understanding of the subject matter. The best network engineers eat, breathe, and drink this type of technology. They keep up on top of the latest trends during their free time and are thrilled to learn about new developments in the field.
|
||||
|
||||
**Detail Oriented**
|
||||
Networking has a lot of moving parts and various types of software and hardware to work with. Paying close attention to all of the details ensures that the system is being monitored correctly and nothing gets lost in the shuffle. When data breaches are prevalent in the business world, stopping an intrusion could mean identifying a small red flag that popped up the day before. Without being alert to these details, the network ends up being vulnerable.
|
||||
|
||||
**Problem Solving**
|
||||
One of the most used skills in network engineering is problem-solving. Everything from troubleshooting issues for users to look for ways to improve the performance of the network requires it. When a worker in this field can quickly and efficiently solve issues through an analytical mindset, they free up a lot of time for strategic decision-making.
|
||||
|
||||
**Team Coordination**
|
||||
Many organizations have teams collaborating together across departments. The network engineer role may be a small part of the team or put in a management position based on the resources required for the project. Working with multiple teams requires strong people management skills and understanding how to move towards a common goal.
|
||||
|
||||
**Ongoing Education**
|
||||
Many continued education opportunities exist for network engineering. Many organizations offer certifications in specific networking technologies, whether the person is learning about a particular server operating system or branching out into subject areas that are related to networking. A drive for ongoing education means that the network engineer will always have their skills updated to adapt to the latest technology changes in the marketplace. Additionally, when these workers love to learn, they also seek out self-instruction opportunities. For example, they could [_read this guide_][3] to learn more about how VPN protocols work.
|
||||
|
||||
**Documentation**
|
||||
Strong writing skills may not be the first characteristic that comes to mind when someone thinks about a network engineer. However, it’s essential when it comes to writing technical documentation. Well-structured and clear documentation allows the network engineer to share information about the network with other people in the organization. If that person ends up leaving the company, the networking protocols, procedures and configuration remain in place because all of the data is available and understandable.
|
||||
|
||||
**Jargon-free Communication**
|
||||
Network engineers have frequent conversations with stakeholders and end users, who may not have a strong IT background. The common jargon used for talking with other members of the IT teams would leave this group confused and not understanding what you’re saying. When the network engineer can explain technology in simple terms, it makes it easier to get the resources and budget that they need to effectively support the company’s networking needs.
|
||||
|
||||
**Proactive Approaches**
|
||||
Some network engineers rely on reactive approaches to fix problems when they occur. If data breaches aren’t prevented before they impact the organization, then it ends up being an expensive endeavor. A reactive approach is sometimes compared to running around and putting out fires the entire day. A proactive approach is more strategic. Network engineers put systems, policies and procedures in place that prevent the intrusion in the first place. They pick up on small issues and tackle them as soon as they show up, rather than waiting for something to break. It’s easier to improve network performance because many of the low-level problems are eliminated through the network design or other technology that was implemented.
|
||||
|
||||
**Independent**
|
||||
Network engineers often have to work on tasks without a lot of oversight. Depending on the company’s budget, they may be the only person in their role in the entire organization. Working independently requires the employee to be driven and a self-starter. They must be able to keep themselves on task and stick to the schedule that’s laid out for that particular project. In the event of a disaster, the network engineer may need to step into a leadership role to guide the recovery process.
|
||||
|
||||
**Fast Learner**
|
||||
Technology changes all the time, and the interactions between new hardware and software may not be expected. A fast learner can quickly pick up the most important details about a piece of technology so that they can effectively troubleshoot it or optimize it.
|
||||
|
||||
**On-Call**
|
||||
Disasters can strike a network at any time, and unexpected downtime is one of the worst things that can happen to a modern business. The mission-critical systems have to come up as soon as possible, which means that network engineers may need to take on-call shifts. One of the keys to being on-call is to be ready to act at a moment’s notice, even if it’s the middle of the night.
|
||||
|
||||
**Reliability**
|
||||
Few businesses can operate without their network being up and available. If critical software or hardware are not available, then the entire business may find itself at a standstill. Customers get upset that they can’t access the website or reach anyone in the company, employees are frustrated because they’re falling behind on their projects, and management is running around trying to get everything back up and running. As a network engineer, reliability is the key. Being available makes a big difference in resolving these types of problems, and always showing up on time and on schedule goes a long way towards cementing someone as a great network engineer.
|
||||
|
||||
![Avatar][4]
|
||||
|
||||
[Christopher Nichols][5]
|
||||
|
||||
[![][6]][7]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensourceforu.com/2019/11/what-it-takes-to-be-a-successful-network-engineer/
|
||||
|
||||
作者:[Christopher Nichols][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://opensourceforu.com/author/christopher-nichols/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2015/03/Network-cable-with-router.jpg?resize=696%2C372&ssl=1 (Network cable with router)
|
||||
[2]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2015/03/Network-cable-with-router.jpg?fit=1329%2C710&ssl=1
|
||||
[3]: https://surfshark.com/learn/vpn-protocols
|
||||
[4]: https://secure.gravatar.com/avatar/92e286970e06818292d5ce792b67a662?s=100&r=g
|
||||
[5]: https://opensourceforu.com/author/christopher-nichols/
|
||||
[6]: http://opensourceforu.com/wp-content/uploads/2013/10/assoc.png
|
||||
[7]: https://feedburner.google.com/fb/a/mailverify?uri=LinuxForYou&loc=en_US
|
@ -1,346 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Linux permissions 101)
|
||||
[#]: via: (https://opensource.com/article/19/8/linux-permissions-101)
|
||||
[#]: author: (Alex Juarez https://opensource.com/users/mralexjuarezhttps://opensource.com/users/marcobravohttps://opensource.com/users/greg-p)
|
||||
|
||||
Linux permissions 101
|
||||
======
|
||||
Knowing how to control users' access to files is a fundamental system
|
||||
administration skill.
|
||||
![Penguins][1]
|
||||
|
||||
Understanding Linux permissions and how to control which users have access to files is a fundamental skill for systems administration.
|
||||
|
||||
This article will cover standard Linux file systems permissions, dig further into special permissions, and wrap up with an explanation of default permissions using **umask**.
|
||||
|
||||
### Understanding the ls command output
|
||||
|
||||
Before we can talk about how to modify permissions, we need to know how to view them. The **ls** command with the long listing argument (**-l**) gives us a lot of information about a file.
|
||||
|
||||
|
||||
```
|
||||
$ ls -lAh
|
||||
total 20K
|
||||
-rwxr-xr--+ 1 root root 0 Mar 4 19:39 file1
|
||||
-rw-rw-rw-. 1 root root 0 Mar 4 19:39 file10
|
||||
-rwxrwxr--+ 1 root root 0 Mar 4 19:39 file2
|
||||
-rw-rw-rw-. 1 root root 0 Mar 4 19:39 file8
|
||||
-rw-rw-rw-. 1 root root 0 Mar 4 19:39 file9
|
||||
drwxrwxrwx. 2 root root 4.0K Mar 4 20:04 testdir
|
||||
```
|
||||
|
||||
To understand what this means, let's break down the output regarding the permissions into individual sections. It will be easier to reference each section individually.
|
||||
|
||||
Take a look at each component of the final line in the output above:
|
||||
|
||||
|
||||
```
|
||||
`drwxrwxrwx. 2 root root 4.0K Mar 4 20:04 testdir`
|
||||
```
|
||||
|
||||
Section 1 | Section 2 | Section 3 | Section 4 | Section 5 | Section 6 | Section 7
|
||||
---|---|---|---|---|---|---
|
||||
d | rwx | rwx | rwx | . | root | root
|
||||
|
||||
Section 1 (on the left) reveals what type of file it is.
|
||||
|
||||
d | Directory
|
||||
---|---
|
||||
- | Regular file
|
||||
l | A soft link
|
||||
|
||||
The [info page][2] for **ls** has a full listing of the different file types.
|
||||
|
||||
Each file has three modes of access:
|
||||
|
||||
* the owner
|
||||
* the group
|
||||
* all others
|
||||
|
||||
|
||||
|
||||
Sections 2, 3, and 4 refer to the user, group, and "other users" permissions. And each section can include a combination of **r** (read), **w** (write), and **x** (executable) permissions.
|
||||
|
||||
Each of the permissions is also assigned a numerical value, which is important when talking about the octal representation of permissions.
|
||||
|
||||
Permission | Octal Value
|
||||
---|---
|
||||
Read | 4
|
||||
Write | 2
|
||||
Execute | 1
|
||||
|
||||
Section 5 details any alternative access methods, such as SELinux or File Access Control List (FACL).
|
||||
|
||||
Method | Character
|
||||
---|---
|
||||
No other method | -
|
||||
SELinux | .
|
||||
FACLs | +
|
||||
Any combination of methods | +
|
||||
|
||||
Sections 6 and 7 are the names of the owner and the group, respectively.
|
||||
|
||||
### Using chown and chmod
|
||||
|
||||
#### The chown command
|
||||
|
||||
The **chown** (change ownership) command is used to change a file's user and group ownership.
|
||||
|
||||
To change both the user and group ownership of the file **foo** to **root**, we can use these commands:
|
||||
|
||||
|
||||
```
|
||||
$ chown root:root foo
|
||||
$ chown root: foo
|
||||
```
|
||||
|
||||
Running the command with the user followed by a colon (**:**) sets both the user and group ownership.
|
||||
|
||||
To set only the user ownership of the file **foo** to the **root** user, enter:
|
||||
|
||||
|
||||
```
|
||||
`$ chown root foo`
|
||||
```
|
||||
|
||||
To change only the group ownership of the file **foo**, precede the group with a colon:
|
||||
|
||||
|
||||
```
|
||||
`$ chown :root foo`
|
||||
```
|
||||
|
||||
#### The chmod command
|
||||
|
||||
The **chmod** (change mode) command controls file permissions for the owner, group, and all other users who are neither the owner nor part of the group associated with the file.
|
||||
|
||||
The **chmod** command can set permissions in both octal (e.g., 755, 644, etc.) and symbolic (e.g., u+rwx, g-rwx, o=rw) formatting.
|
||||
|
||||
Octal notation assigns 4 "points" to **read**, 2 to **write**, and 1 to **execute**. If we want to assign the user **read** permissions, we assign 4 to the first slot, but if we want to add **write** permissions, we must add 2. If we want to add **execute**, then we add 1. We do this for each permission type: owner, group, and others.
|
||||
|
||||
For example, if we want to assign **read**, **write**, and **execute** to the owner of the file, but only **read** and **execute** to group members and all other users, we would use 755 in octal formatting. That's all permission bits for the owner (4+2+1), but only a 4 and 1 for the group and others (4+1).
|
||||
|
||||
> The breakdown for that is: 4+2+1=7; 4+1=5; and 4+1=5.
|
||||
|
||||
If we wanted to assign **read** and **write** to the owner of the file but only **read** to members of the group and all other users, we could use **chmod** as follows:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod 644 foo_file`
|
||||
```
|
||||
|
||||
In the examples below, we use symbolic notation in different groupings. Note the letters **u**, **g**, and **o** represent **user**, **group**, and **other**. We use **u**, **g**, and **o** in conjunction with **+**, **-**, or **=** to add, remove, or set permission bits.
|
||||
|
||||
To add the **execute** bit to the ownership permission set:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod u+x foo_file`
|
||||
```
|
||||
|
||||
To remove **read**, **write**, and **execute** from members of the group:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod g-rwx foo_file`
|
||||
```
|
||||
|
||||
To set the ownership for all other users to **read** and **write**:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod o=rw`
|
||||
```
|
||||
|
||||
### The special bits: Set UID, set GID, and sticky bits
|
||||
|
||||
In addition to the standard permissions, there are a few special permission bits that have some useful benefits.
|
||||
|
||||
#### Set user ID (suid)
|
||||
|
||||
When **suid** is set on a file, an operation executes as the owner of the file, not the user running the file. A [good example][3] of this is the **passwd** command. It needs the **suid** bit to be set so that changing a password runs with root permissions.
|
||||
|
||||
|
||||
```
|
||||
$ ls -l /bin/passwd
|
||||
-rwsr-xr-x. 1 root root 27832 Jun 10 2014 /bin/passwd
|
||||
```
|
||||
|
||||
An example of setting the **suid** bit would be:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod u+s /bin/foo_file_name`
|
||||
```
|
||||
|
||||
#### Set group ID (sgid)
|
||||
|
||||
The **sgid** bit is similar to the **suid** bit in the sense that the operations are done under the group ownership of the directory instead of the user running the command.
|
||||
|
||||
An example of using **sgid** would be if multiple users are working out of the same directory, and every file created in the directory needs to have the same group permissions. The example below creates a directory called **collab_dir**, sets the **sgid** bit, and changes the group ownership to **webdev**.
|
||||
|
||||
|
||||
```
|
||||
$ mkdir collab_dir
|
||||
$ chmod g+s collab_dir
|
||||
$ chown :webdev collab_dir
|
||||
```
|
||||
|
||||
Now any file created in the directory will have the group ownership of **webdev** instead of the user who created the file.
|
||||
|
||||
|
||||
```
|
||||
$ cd collab_dir
|
||||
$ touch file-sgid
|
||||
$ ls -lah file-sgid
|
||||
-rw-r--r--. 1 root webdev 0 Jun 12 06:04 file-sgid
|
||||
```
|
||||
|
||||
#### The "sticky" bit
|
||||
|
||||
The sticky bit denotes that only the owner of a file can delete the file, even if group permissions would otherwise allow it. This setting usually makes the most sense on a common or collaborative directory such as **/tmp**. In the example below, the **t** in the **execute** column of the **all others** permission set indicates that the sticky bit has been applied.
|
||||
|
||||
|
||||
```
|
||||
$ ls -ld /tmp
|
||||
drwxrwxrwt. 8 root root 4096 Jun 12 06:07 /tmp/
|
||||
```
|
||||
|
||||
Keep in mind this does not prevent somebody from editing the file; it just keeps them from deleting the contents of a directory.
|
||||
|
||||
We set the sticky bit with:
|
||||
|
||||
|
||||
```
|
||||
`$ chmod o+t foo_dir`
|
||||
```
|
||||
|
||||
On your own, try setting the sticky bit on a directory and give it full group permissions so that multiple users can read, write and execute on the directory because they are in the same group.
|
||||
|
||||
From there, create files as each user and then try to delete them as the other.
|
||||
|
||||
If everything is configured correctly, one user should not be able to delete users from the other user.
|
||||
|
||||
Note that each of these bits can also be set in octal format with SUID=4, SGID=2, and Sticky=1.
|
||||
|
||||
|
||||
```
|
||||
$ chmod 4744
|
||||
$ chmod 2644
|
||||
$ chmod 1755
|
||||
```
|
||||
|
||||
#### Uppercase or lowercase?
|
||||
|
||||
If you are setting the special bits and see an uppercase **S** or **T** instead of lowercase (as we've seen until this point), it is because the underlying execute bit is not present. To demonstrate, the following example creates a file with the sticky bit set. We can then add/remove the execute bit to demonstrate the case change.
|
||||
|
||||
|
||||
```
|
||||
$ touch file cap-ST-demo
|
||||
$ chmod 1755 cap-ST-demo
|
||||
$ ls -l cap-ST-demo
|
||||
-rwxr-xr-t. 1 root root 0 Jun 12 06:16 cap-ST-demo
|
||||
|
||||
$ chmod o-x cap-X-demo
|
||||
$ ls -l cap-X-demo
|
||||
-rwxr-xr-T. 1 root root 0 Jun 12 06:16 cap-ST-demo
|
||||
```
|
||||
|
||||
#### Setting the execute bit conditionally
|
||||
|
||||
To this point, we've set the **execute** bit using a lowercase **x**, which sets it without asking any questions. We have another option: using an uppercase **X** instead of lowercase will set the **execute** bit only if it is already present somewhere in the permission group. This can be a difficult concept to explain, but the demo below will help illustrate it. Notice here that after trying to add the **execute** bit to the group privileges, it is not applied.
|
||||
|
||||
|
||||
```
|
||||
$ touch cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r--r--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
$ chmod g+X cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r--r--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
```
|
||||
|
||||
In this similar example, we add the execute bit first to the group permissions using the lowercase **x** and then use the uppercase **X** to add permissions for all other users. This time, the uppercase **X** sets the permissions.
|
||||
|
||||
|
||||
```
|
||||
$ touch cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r--r--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
$ chmod g+x cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r-xr--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
$ chmod g+x cap-X-file
|
||||
$ chmod o+X cap-X-file
|
||||
ls -l cap-X-file
|
||||
-rw-r-xr-x. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
```
|
||||
|
||||
### Understanding umask
|
||||
|
||||
The **umask** masks (or "blocks off") bits from the default permission set in order to define permissions for a file or directory. For example, a 2 in the **umask** output indicates it is blocking the **write** bit from a file, at least by default.
|
||||
|
||||
Using the **umask** command without any arguments allows us to see the current **umask** setting. There are four columns: the first is reserved for the special suid, sgid, or sticky bit, and the remaining three represent the owner, group, and other permissions.
|
||||
|
||||
|
||||
```
|
||||
$ umask
|
||||
0022
|
||||
```
|
||||
|
||||
To understand what this means, we can execute **umask** with a **-S** (as shown below) to get the result of masking the bits. For instance, because of the **2** value in the third column, the **write** bit is masked off from the group and other sections; only **read** and **execute** can be assigned for those.
|
||||
|
||||
|
||||
```
|
||||
$ umask -S
|
||||
u=rwx,g=rx,o=rx
|
||||
```
|
||||
|
||||
To see what the default permission set is for files and directories, let's set our **umask** to all zeros. This means that we are not masking off any bits when we create a file.
|
||||
|
||||
|
||||
```
|
||||
$ umask 000
|
||||
$ umask -S
|
||||
u=rwx,g=rwx,o=rwx
|
||||
|
||||
$ touch file-umask-000
|
||||
$ ls -l file-umask-000
|
||||
-rw-rw-rw-. 1 root root 0 Jul 17 22:03 file-umask-000
|
||||
```
|
||||
|
||||
Now when we create a file, we see the default permissions are **read** (4) and **write** (2) for all sections, which would equate to 666 in octal representation.
|
||||
|
||||
We can do the same for a directory and see its default permissions are 777. We need the **execute** bit on directories so we can traverse through them.
|
||||
|
||||
|
||||
```
|
||||
$ mkdir dir-umask-000
|
||||
$ ls -ld dir-umask-000
|
||||
drwxrwxrwx. 2 root root 4096 Jul 17 22:03 dir-umask-000/
|
||||
```
|
||||
|
||||
### Conclusion
|
||||
|
||||
There are many other ways an administrator can control access to files on a system. These permissions are basic to Linux, and we can build upon these fundamental aspects. If your work takes you into FACLs or SELinux, you will see that they also build upon these first rules of file access.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/linux-permissions-101
|
||||
|
||||
作者:[Alex Juarez][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/mralexjuarezhttps://opensource.com/users/marcobravohttps://opensource.com/users/greg-p
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux-penguins.png?itok=yKOpaJM_ (Penguins)
|
||||
[2]: https://www.gnu.org/software/texinfo/manual/info-stnd/info-stnd.html
|
||||
[3]: https://www.theurbanpenguin.com/using-a-simple-c-program-to-explain-the-suid-permission/
|
@ -1,272 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (jdh8383)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to program with Bash: Syntax and tools)
|
||||
[#]: via: (https://opensource.com/article/19/10/programming-bash-part-1)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
How to program with Bash: Syntax and tools
|
||||
======
|
||||
Learn basic Bash programming syntax and tools, as well as how to use
|
||||
variables and control operators, in the first article in this three-part
|
||||
series.
|
||||
![bash logo on green background][1]
|
||||
|
||||
A shell is the command interpreter for the operating system. Bash is my favorite shell, but every Linux shell interprets the commands typed by the user or sysadmin into a form the operating system can use. When the results are returned to the shell program, it sends them to STDOUT which, by default, [displays them in the terminal][2]. All of the shells I am familiar with are also programming languages.
|
||||
|
||||
Features like tab completion, command-line recall and editing, and shortcuts like aliases all contribute to its value as a powerful shell. Its default command-line editing mode uses Emacs, but one of my favorite Bash features is that I can change it to Vi mode to use editing commands that are already part of my muscle memory.
|
||||
|
||||
However, if you think of Bash solely as a shell, you miss much of its true power. While researching my three-volume [Linux self-study course][3] (on which this series of articles is based), I learned things about Bash that I'd never known in over 20 years of working with Linux. Some of these new bits of knowledge relate to its use as a programming language. Bash is a powerful programming language, one perfectly designed for use on the command line and in shell scripts.
|
||||
|
||||
This three-part series explores using Bash as a command-line interface (CLI) programming language. This first article looks at some simple command-line programming with Bash, variables, and control operators. The other articles explore types of Bash files; string, numeric, and miscellaneous logical operators that provide execution-flow control logic; different types of shell expansions; and the **for**, **while**, and **until** loops that enable repetitive operations. They will also look at some commands that simplify and support the use of these tools.
|
||||
|
||||
### The shell
|
||||
|
||||
A shell is the command interpreter for the operating system. Bash is my favorite shell, but every Linux shell interprets the commands typed by the user or sysadmin into a form the operating system can use. When the results are returned to the shell program, it displays them in the terminal. All of the shells I am familiar with are also programming languages.
|
||||
|
||||
Bash stands for Bourne Again Shell because the Bash shell is [based upon][4] the older Bourne shell that was written by Steven Bourne in 1977. Many [other shells][5] are available, but these are the four I encounter most frequently:
|
||||
|
||||
* **csh:** The C shell for programmers who like the syntax of the C language
|
||||
* **ksh:** The Korn shell, written by David Korn and popular with Unix users
|
||||
* **tcsh:** A version of csh with more ease-of-use features
|
||||
* **zsh:** The Z shell, which combines many features of other popular shells
|
||||
|
||||
|
||||
|
||||
All shells have built-in commands that supplement or replace the ones provided by the core utilities. Open the shell's man page and find the "BUILT-INS" section to see the commands it provides.
|
||||
|
||||
Each shell has its own personality and syntax. Some will work better for you than others. I have used the C shell, the Korn shell, and the Z shell. I still like the Bash shell more than any of them. Use the one that works best for you, although that might require you to try some of the others. Fortunately, it's quite easy to change shells.
|
||||
|
||||
All of these shells are programming languages, as well as command interpreters. Here's a quick tour of some programming constructs and tools that are integral parts of Bash.
|
||||
|
||||
### Bash as a programming language
|
||||
|
||||
Most sysadmins have used Bash to issue commands that are usually fairly simple and straightforward. But Bash can go beyond entering single commands, and many sysadmins create simple command-line programs to perform a series of tasks. These programs are common tools that can save time and effort.
|
||||
|
||||
My objective when writing CLI programs is to save time and effort (i.e., to be the lazy sysadmin). CLI programs support this by listing several commands in a specific sequence that execute one after another, so you do not need to watch the progress of one command and type in the next command when the first finishes. You can go do other things and not have to continually monitor the progress of each command.
|
||||
|
||||
### What is "a program"?
|
||||
|
||||
The Free On-line Dictionary of Computing ([FOLDOC][6]) defines a program as: "The instructions executed by a computer, as opposed to the physical device on which they run." Princeton University's [WordNet][7] defines a program as: "…a sequence of instructions that a computer can interpret and execute…" [Wikipedia][8] also has a good entry about computer programs.
|
||||
|
||||
Therefore, a program can consist of one or more instructions that perform a specific, related task. A computer program instruction is also called a program statement. For sysadmins, a program is usually a sequence of shell commands. All the shells available for Linux, at least the ones I am familiar with, have at least a basic form of programming capability, and Bash, the default shell for most Linux distributions, is no exception.
|
||||
|
||||
While this series uses Bash (because it is so ubiquitous), if you use a different shell, the general programming concepts will be the same, although the constructs and syntax may differ somewhat. Some shells may support some features that others do not, but they all provide some programming capability. Shell programs can be stored in a file for repeated use, or they may be created on the command line as needed.
|
||||
|
||||
### Simple CLI programs
|
||||
|
||||
The simplest command-line programs are one or two consecutive program statements, which may be related or not, that are entered on the command line before the **Enter** key is pressed. The second statement in a program, if there is one, might be dependent upon the actions of the first, but it does not need to be.
|
||||
|
||||
There is also one bit of syntactical punctuation that needs to be clearly stated. When entering a single command on the command line, pressing the **Enter** key terminates the command with an implicit semicolon (**;**). When used in a CLI shell program entered as a single line on the command line, the semicolon must be used to terminate each statement and separate it from the next one. The last statement in a CLI shell program can use an explicit or implicit semicolon.
|
||||
|
||||
### Some basic syntax
|
||||
|
||||
The following examples will clarify this syntax. This program consists of a single command with an explicit terminator:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ echo "Hello world." ;
|
||||
Hello world.
|
||||
```
|
||||
|
||||
That may not seem like much of a program, but it is the first program I encounter with every new programming language I learn. The syntax may be a bit different for each language, but the result is the same.
|
||||
|
||||
Let's expand a little on this trivial but ubiquitous program. Your results will be different from mine because I have done other experiments, while you may have only the default directories and files that are created in the account home directory the first time you log into an account via the GUI desktop.
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ echo "My home directory." ; ls ;
|
||||
My home directory.
|
||||
chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6
|
||||
chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir
|
||||
TestFile1 Desktop dmesg.txt link3 Public testdir Videos
|
||||
TestFile1.dos dmesg1.txt Documents Music random.txt testdir1
|
||||
```
|
||||
|
||||
That makes a bit more sense. The results are related, but the individual program statements are independent of each other. Notice that I like to put spaces before and after the semicolon because it makes the code a bit easier to read. Try that little CLI program again without an explicit semicolon at the end:
|
||||
|
||||
|
||||
```
|
||||
`[student@studentvm1 ~]$ echo "My home directory." ; ls`
|
||||
```
|
||||
|
||||
There is no difference in the output.
|
||||
|
||||
### Something about variables
|
||||
|
||||
Like all programming languages, the Bash shell can deal with variables. A variable is a symbolic name that refers to a specific location in memory that contains a value of some sort. The value of a variable is changeable, i.e., it is variable.
|
||||
|
||||
Bash does not type variables like C and related languages, defining them as integers, floating points, or string types. In Bash, all variables are strings. A string that is an integer can be used in integer arithmetic, which is the only type of math that Bash is capable of doing. If more complex math is required, the [**bc** command][9] can be used in CLI programs and scripts.
|
||||
|
||||
Variables are assigned values and can be used to refer to those values in CLI programs and scripts. The value of a variable is set using its name but not preceded by a **$** sign. The assignment **VAR=10** sets the value of the variable VAR to 10. To print the value of the variable, you can use the statement **echo $VAR**. Start with text (i.e., non-numeric) variables.
|
||||
|
||||
Bash variables become part of the shell environment until they are unset.
|
||||
|
||||
Check the initial value of a variable that has not been assigned; it should be null. Then assign a value to the variable and print it to verify its value. You can do all of this in a single CLI program:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ;
|
||||
|
||||
Hello World
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
_Note: The syntax of variable assignment is very strict. There must be no spaces on either side of the equal (**=**) sign in the assignment statement._
|
||||
|
||||
The empty line indicates that the initial value of **MyVar** is null. Changing and setting the value of a variable are done the same way. This example shows both the original and the new value.
|
||||
|
||||
As mentioned, Bash can perform integer arithmetic calculations, which is useful for calculating a reference to the location of an element in an array or doing simple math problems. It is not suitable for scientific computing or anything that requires decimals, such as financial calculations. There are much better tools for those types of calculations.
|
||||
|
||||
Here's a simple calculation:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"
|
||||
Result = 63
|
||||
```
|
||||
|
||||
What happens when you perform a math operation that results in a floating-point number?
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1/Var2))"
|
||||
Result = 0
|
||||
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var2/Var1))"
|
||||
Result = 1
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
The result is the nearest integer. Notice that the calculation was performed as part of the **echo** statement. The math is performed before the enclosing echo command due to the Bash order of precedence. For details see the Bash man page and search "precedence."
|
||||
|
||||
### Control operators
|
||||
|
||||
Shell control operators are one of the syntactical operators for easily creating some interesting command-line programs. The simplest form of CLI program is just stringing several commands together in a sequence on the command line:
|
||||
|
||||
|
||||
```
|
||||
`command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;`
|
||||
```
|
||||
|
||||
Those commands all run without a problem so long as no errors occur. But what happens when an error occurs? You can anticipate and allow for errors using the built-in **&&** and **||** Bash control operators. These two control operators provide some flow control and enable you to alter the sequence of code execution. The semicolon is also considered to be a Bash control operator, as is the newline character.
|
||||
|
||||
The **&&** operator simply says, "if command1 is successful, then run command2. If command1 fails for any reason, then command2 is skipped." That syntax looks like this:
|
||||
|
||||
|
||||
```
|
||||
`command1 && command2`
|
||||
```
|
||||
|
||||
Now, look at some commands that will create a new directory and—if it's successful—make it the present working directory (PWD). Ensure that your home directory (**~**) is the PWD. Try this first in **/root**, a directory that you do not have access to:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir/ && cd $Dir
|
||||
mkdir: cannot create directory '/root/testdir/': Permission denied
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
The error was emitted by the **mkdir** command. You did not receive an error indicating that the file could not be created because the creation of the directory failed. The **&&** control operator sensed the non-zero return code, so the **touch** command was skipped. Using the **&&** control operator prevents the **touch** command from running because there was an error in creating the directory. This type of command-line program flow control can prevent errors from compounding and making a real mess of things. But it's time to get a little more complicated.
|
||||
|
||||
The **||** control operator allows you to add another program statement that executes when the initial program statement returns a code greater than zero. The basic syntax looks like this:
|
||||
|
||||
|
||||
```
|
||||
`command1 || command2`
|
||||
```
|
||||
|
||||
This syntax reads, "If command1 fails, execute command2." That implies that if command1 succeeds, command2 is skipped. Try this by attempting to create a new directory:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir || echo "$Dir was not created."
|
||||
mkdir: cannot create directory '/root/testdir': Permission denied
|
||||
/root/testdir was not created.
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
This is exactly what you would expect. Because the new directory could not be created, the first command failed, which resulted in the execution of the second command.
|
||||
|
||||
Combining these two operators provides the best of both. The control operator syntax using some flow control takes this general form when the **&&** and **||** control operators are used:
|
||||
|
||||
|
||||
```
|
||||
`preceding commands ; command1 && command2 || command3 ; following commands`
|
||||
```
|
||||
|
||||
This syntax can be stated like so: "If command1 exits with a return code of 0, then execute command2, otherwise execute command3." Try it:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
|
||||
mkdir: cannot create directory '/root/testdir': Permission denied
|
||||
/root/testdir was not created.
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
Now try the last command again using your home directory instead of the **/root** directory. You will have permission to create this directory:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
The control operator syntax, like **command1 && command2**, works because every command sends a return code (RC) to the shell that indicates if it completed successfully or whether there was some type of failure during execution. By convention, an RC of zero (0) indicates success, and any positive number indicates some type of failure. Some of the tools sysadmins use just return a one (1) to indicate a failure, but many use other codes to indicate the type of failure that occurred.
|
||||
|
||||
The Bash shell variable **$?** contains the RC from the last command. This RC can be checked very easily by a script, the next command in a list of commands, or even the sysadmin directly. Start by running a simple command and immediately checking the RC. The RC will always be for the last command that ran before you looked at it.
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ll ; echo "RC = $?"
|
||||
total 1264
|
||||
drwxrwxr-x 2 student student 4096 Mar 2 08:21 chapter25
|
||||
drwxrwxr-x 2 student student 4096 Mar 21 15:27 chapter26
|
||||
-rwxr-xr-x 1 student student 92 Mar 20 15:53 TestFile1
|
||||
<snip>
|
||||
drwxrwxr-x. 2 student student 663552 Feb 21 14:12 testdir
|
||||
drwxr-xr-x. 2 student student 4096 Dec 22 13:15 Videos
|
||||
RC = 0
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
The RC, in this case, is zero, which means the command completed successfully. Now try the same command on root's home directory, a directory you do not have permissions for:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ll /root ; echo "RC = $?"
|
||||
ls: cannot open directory '/root': Permission denied
|
||||
RC = 2
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
In this case, the RC is two; this means permission was denied for a non-root user to access a directory to which the user is not permitted access. The control operators use these RCs to enable you to alter the sequence of program execution.
|
||||
|
||||
### Summary
|
||||
|
||||
This article looked at Bash as a programming language and explored its basic syntax as well as some basic tools. It showed how to print data to STDOUT and how to use variables and control operators. The next article in this series looks at some of the many Bash logical operators that control the flow of instruction execution.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/programming-bash-part-1
|
||||
|
||||
作者:[David Both][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/dboth
|
||||
[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://opensource.com/article/18/10/linux-data-streams
|
||||
[3]: http://www.both.org/?page_id=1183
|
||||
[4]: https://opensource.com/19/9/command-line-heroes-bash
|
||||
[5]: https://en.wikipedia.org/wiki/Comparison_of_command_shells
|
||||
[6]: http://foldoc.org/program
|
||||
[7]: https://wordnet.princeton.edu/
|
||||
[8]: https://en.wikipedia.org/wiki/Computer_program
|
||||
[9]: https://www.gnu.org/software/bc/manual/html_mono/bc.html
|
@ -1,263 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wenwensnow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to dual boot Windows 10 and Debian 10)
|
||||
[#]: via: (https://www.linuxtechi.com/dual-boot-windows-10-debian-10/)
|
||||
[#]: author: (James Kiarie https://www.linuxtechi.com/author/james/)
|
||||
|
||||
How to dual boot Windows 10 and Debian 10
|
||||
======
|
||||
|
||||
So, you finally made the bold decision to try out **Linux** after much convincing. However, you do not want to let go of your Windows 10 operating system yet as you will still be needing it before you learn the ropes on Linux. Thankfully, you can easily have a dual boot setup that allows you to switch to either of the operating systems upon booting your system. In this guide, you will learn how to **dual boot Windows 10 alongside Debian 10**.
|
||||
|
||||
[![How-to-dual-boot-Windows-and-Debian10][1]][2]
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you get started, ensure you have the following:
|
||||
|
||||
* A bootable USB or DVD of Debian 10
|
||||
* A fast and stable internet connection ( For installation updates & third party applications)
|
||||
|
||||
|
||||
|
||||
Additionally, it worth paying attention to how your system boots (UEFI or Legacy) and ensure both the operating systems boot using the same boot mode.
|
||||
|
||||
### Step 1: Create a free partition on your hard drive
|
||||
|
||||
To start off, you need to create a free partition on your hard drive. This is the partition where Debian will be installed during the installation process. To achieve this, you will invoke the disk management utility as shown:
|
||||
|
||||
Press **Windows Key + R** to launch the Run dialogue. Next, type **diskmgmt.msc** and hit **ENTER**
|
||||
|
||||
[![Launch-Run-dialogue][1]][3]
|
||||
|
||||
This launches the **disk management** window displaying all the drives existing on your Windows system.
|
||||
|
||||
[![Disk-management][1]][4]
|
||||
|
||||
Next, you need to create a free space for Debian installation. To do this, you need to shrink a partition from one of the volumes and create a new unallocated partition. In this case, I will create a **30 GB** partition from Volume D.
|
||||
|
||||
To shrink a volume, right-click on it and select the ‘**shrink**’ option
|
||||
|
||||
[![Shrink-volume][1]][5]
|
||||
|
||||
In the pop-up dialogue, define the size that you want to shrink your space. Remember, this will be the disk space on which Debian 10 will be installed. In my case, I selected **30000MB ( Approximately 30 GB)**. Once done, click on ‘**Shrink**’.
|
||||
|
||||
[![Shrink-space][1]][6]
|
||||
|
||||
After the shrinking operation completes, you should have an unallocated partition as shown:
|
||||
|
||||
[![Unallocated-partition][1]][7]
|
||||
|
||||
Perfect! We are now good to go and ready to begin the installation process.
|
||||
|
||||
### Step 2: Begin the installation of Debian 10
|
||||
|
||||
With the free partition already created, plug in your bootable USB drive or insert the DVD installation medium in your PC and reboot your system. Be sure to make changes to the **boot order** in the **BIOS** set up by pressing the function keys (usually, **F9, F10 or F12** depending on the vendor). This is crucial so that the PC boots into your installation medium. Saves the BIOS settings and reboot.
|
||||
|
||||
A new grub menu will be displayed as shown below: Click on ‘**Graphical install**’
|
||||
|
||||
[![Graphical-Install-Debian10][1]][8]
|
||||
|
||||
In the next step, select your **preferred language** and click ‘**Continue**’
|
||||
|
||||
[![Select-Language-Debian10][1]][9]
|
||||
|
||||
Next, select your **location** and click ‘**Continue**’. Based on this location the time will automatically be selected for you. If you cannot find you located, scroll down and click on ‘**other**’ then select your location.
|
||||
|
||||
[![Select-location-Debain10][1]][10]
|
||||
|
||||
Next, select your **keyboard** layout.
|
||||
|
||||
[![Configure-Keyboard-layout-Debain10][1]][11]
|
||||
|
||||
In the next step, specify your system’s **hostname** and click ‘**Continue**’
|
||||
|
||||
[![Set-hostname-Debian10][1]][12]
|
||||
|
||||
Next, specify the **domain name**. If you are not in a domain environment, simply click on the ‘**continue**’ button.
|
||||
|
||||
[![Set-domain-name-Debian10][1]][13]
|
||||
|
||||
In the next step, specify the **root password** as shown and click ‘**continue**’.
|
||||
|
||||
[![Set-root-Password-Debian10][1]][14]
|
||||
|
||||
In the next step, specify the full name of the user for the account and click ‘**continue**’
|
||||
|
||||
[![Specify-fullname-user-debain10][1]][15]
|
||||
|
||||
Then set the account name by specifying the **username** associated with the account
|
||||
|
||||
[![Specify-username-Debian10][1]][16]
|
||||
|
||||
Next, specify the username’s password as shown and click ‘**continue**’
|
||||
|
||||
[![Specify-user-password-Debian10][1]][17]
|
||||
|
||||
Next, specify your **timezone**
|
||||
|
||||
[![Configure-timezone-Debian10][1]][18]
|
||||
|
||||
At this point, you need to create partitions for your Debian 10 installation. If you are an inexperienced user, Click on the ‘**Use the largest continuous free space**’ and click ‘**continue**’.
|
||||
|
||||
[![Use-largest-continuous-free-space-debian10][1]][19]
|
||||
|
||||
However, if you are more knowledgeable about creating partitions, select the ‘**Manual**’ option and click ‘**continue**’
|
||||
|
||||
[![Select-Manual-Debain10][1]][20]
|
||||
|
||||
Thereafter, select the partition labeled ‘**FREE SPACE**’ and click ‘**continue**’ . Next click on ‘**Create a new partition**’.
|
||||
|
||||
[![Create-new-partition-Debain10][1]][21]
|
||||
|
||||
In the next window, first, define the size of swap space, In my case, I specified **2GB**. Click **Continue**.
|
||||
|
||||
[![Define-swap-space-debian10][1]][22]
|
||||
|
||||
Next, click on ‘’**Primary**’ on the next screen and click ‘**continue**’
|
||||
|
||||
[![Partition-Disks-Primary-Debain10][1]][23]
|
||||
|
||||
Select the partition to **start at the beginning** and click continue.
|
||||
|
||||
[![Start-at-the-beginning-Debain10][1]][24]
|
||||
|
||||
Next, click on **Ext 4 journaling file system** and click ‘**continue**’
|
||||
|
||||
[![Select-Ext4-Journaling-system-debain10][1]][25]
|
||||
|
||||
On the next window, select **swap **and click continue
|
||||
|
||||
[![Select-swap-debain10][1]][26]
|
||||
|
||||
Next, click on **done setting the partition** and click continue.
|
||||
|
||||
[![Done-setting-partition-debian10][1]][27]
|
||||
|
||||
Back to the **Partition disks** page, click on **FREE SPACE** and click continue
|
||||
|
||||
[![Click-Free-space-Debain10][1]][28]
|
||||
|
||||
To make your life easy select **Automatically partition the free space** and click **continue**.
|
||||
|
||||
[![Automatically-partition-free-space-Debain10][1]][29]
|
||||
|
||||
Next click on **All files in one partition (recommended for new users)**
|
||||
|
||||
[![All-files-in-one-partition-debian10][1]][30]
|
||||
|
||||
Finally, click on **Finish partitioning and write changes to disk** and click **continue**.
|
||||
|
||||
[![Finish-partitioning-write-changes-to-disk][1]][31]
|
||||
|
||||
Confirm that you want to write changes to disk and click ‘**Yes**’
|
||||
|
||||
[![Write-changes-to-disk-Yes-Debian10][1]][32]
|
||||
|
||||
Thereafter, the installer will begin installing all the requisite software packages.
|
||||
|
||||
When asked if you want to scan another CD, select **No** and click continue
|
||||
|
||||
[![Scan-another-CD-No-Debain10][1]][33]
|
||||
|
||||
Next, select the mirror of the Debian archive closest to you and click ‘Continue’
|
||||
|
||||
[![Debian-archive-mirror-country][1]][34]
|
||||
|
||||
Next, select the **Debian mirror** that is most preferable to you and click ‘**Continue**’
|
||||
|
||||
[![Select-Debian-archive-mirror][1]][35]
|
||||
|
||||
If you plan on using a proxy server, enter its details as shown below, otherwise leave it blank and click ‘continue’
|
||||
|
||||
[![Enter-proxy-details-debian10][1]][36]
|
||||
|
||||
As the installation proceeds, you will be asked if you would like to participate in a **package usage survey**. You can select either option and click ‘continue’ . In my case, I selected ‘**No**’
|
||||
|
||||
[![Participate-in-survey-debain10][1]][37]
|
||||
|
||||
Next, select the packages you need in the **software selection** window and click **continue**.
|
||||
|
||||
[![Software-selection-debian10][1]][38]
|
||||
|
||||
The installation will continue installing the selected packages. At this point, you can take a coffee break as the installation goes on.
|
||||
|
||||
You will be prompted whether to install the grub **bootloader** on **Master Boot Record (MBR)**. Click **Yes** and click **Continue**.
|
||||
|
||||
[![Install-grub-bootloader-debian10][1]][39]
|
||||
|
||||
Next, select the hard drive on which you want to install **grub** and click **Continue**.
|
||||
|
||||
[![Select-hard-drive-install-grub-Debian10][1]][40]
|
||||
|
||||
Finally, the installation will complete, Go ahead and click on the ‘**Continue**’ button
|
||||
|
||||
[![Installation-complete-reboot-debian10][1]][41]
|
||||
|
||||
You should now have a grub menu with both **Windows** and **Debian** listed. To boot to Debian, scroll and click on Debian. Thereafter, you will be prompted with a login screen. Enter your details and hit ENTER.
|
||||
|
||||
[![Debian10-log-in][1]][42]
|
||||
|
||||
And voila! There goes your fresh copy of Debian 10 in a dual boot setup with Windows 10.
|
||||
|
||||
[![Debian10-Buster-Details][1]][43]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxtechi.com/dual-boot-windows-10-debian-10/
|
||||
|
||||
作者:[James Kiarie][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.linuxtechi.com/author/james/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]: https://www.linuxtechi.com/wp-content/uploads/2019/10/How-to-dual-boot-Windows-and-Debian10.jpg
|
||||
[3]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Launch-Run-dialogue.jpg
|
||||
[4]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Disk-management.jpg
|
||||
[5]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Shrink-volume.jpg
|
||||
[6]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Shrink-space.jpg
|
||||
[7]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Unallocated-partition.jpg
|
||||
[8]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Graphical-Install-Debian10.jpg
|
||||
[9]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Language-Debian10.jpg
|
||||
[10]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-location-Debain10.jpg
|
||||
[11]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Configure-Keyboard-layout-Debain10.jpg
|
||||
[12]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Set-hostname-Debian10.jpg
|
||||
[13]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Set-domain-name-Debian10.jpg
|
||||
[14]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Set-root-Password-Debian10.jpg
|
||||
[15]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Specify-fullname-user-debain10.jpg
|
||||
[16]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Specify-username-Debian10.jpg
|
||||
[17]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Specify-user-password-Debian10.jpg
|
||||
[18]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Configure-timezone-Debian10.jpg
|
||||
[19]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Use-largest-continuous-free-space-debian10.jpg
|
||||
[20]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Manual-Debain10.jpg
|
||||
[21]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Create-new-partition-Debain10.jpg
|
||||
[22]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Define-swap-space-debian10.jpg
|
||||
[23]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Partition-Disks-Primary-Debain10.jpg
|
||||
[24]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Start-at-the-beginning-Debain10.jpg
|
||||
[25]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Ext4-Journaling-system-debain10.jpg
|
||||
[26]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-swap-debain10.jpg
|
||||
[27]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Done-setting-partition-debian10.jpg
|
||||
[28]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Click-Free-space-Debain10.jpg
|
||||
[29]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Automatically-partition-free-space-Debain10.jpg
|
||||
[30]: https://www.linuxtechi.com/wp-content/uploads/2019/10/All-files-in-one-partition-debian10.jpg
|
||||
[31]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Finish-partitioning-write-changes-to-disk.jpg
|
||||
[32]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Write-changes-to-disk-Yes-Debian10.jpg
|
||||
[33]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Scan-another-CD-No-Debain10.jpg
|
||||
[34]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Debian-archive-mirror-country.jpg
|
||||
[35]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Debian-archive-mirror.jpg
|
||||
[36]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Enter-proxy-details-debian10.jpg
|
||||
[37]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Participate-in-survey-debain10.jpg
|
||||
[38]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Software-selection-debian10.jpg
|
||||
[39]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Install-grub-bootloader-debian10.jpg
|
||||
[40]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-hard-drive-install-grub-Debian10.jpg
|
||||
[41]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Installation-complete-reboot-debian10.jpg
|
||||
[42]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Debian10-log-in.jpg
|
||||
[43]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Debian10-Buster-Details.jpg
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -1,107 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Keyboard Shortcuts to Speed Up Your Work in Linux)
|
||||
[#]: via: (https://opensourceforu.com/2019/11/keyboard-shortcuts-to-speed-up-your-work-in-linux/)
|
||||
[#]: author: (S Sathyanarayanan https://opensourceforu.com/author/s-sathyanarayanan/)
|
||||
|
||||
Keyboard Shortcuts to Speed Up Your Work in Linux
|
||||
======
|
||||
|
||||
[![Google Keyboard][1]][2]
|
||||
|
||||
_Manipulating the mouse, keyboard and menus takes up a lot of our time, which could be saved by using keyboard shortcuts. These not only save time, but also make the computer user more efficient._
|
||||
|
||||
Did you realise that switching from the keyboard to the mouse while typing takes up to two seconds each time? If a person works for eight hours every day, switching from the keyboard to the mouse once a minute, and there are around 240 working days in a year, the amount of time wasted (as per calculations done by Brainscape) is:
|
||||
_[2 wasted seconds/min] x [480 minutes per day] x 240 working days per year = 64 wasted hours per year_
|
||||
This is equal to eight working days lost and hence learning keyboard shortcuts will increase productivity by 3.3 per cent (_<https://www.brainscape.com/blog/2011/08/keyboard-shortcuts-economy/>_).
|
||||
|
||||
Keyboard shortcuts provide a quicker way to do a task, which otherwise would have had to be done in multiple steps using the mouse and/or the menu. Figure 1 gives a list of a few most frequently used shortcuts in Ubuntu 18.04 Linux OS and the Web browsers. I am omitting the very well-known shortcuts like copy, paste, etc, and the ones which are not used frequently. The readers can refer to online resources for a comprehensive list of shortcuts. Note that the Windows key is renamed as Super key in Linux.
|
||||
|
||||
**General shortcuts**
|
||||
A list of general shortcuts is given below.
|
||||
|
||||
[![][3]][4]
|
||||
**Print Screen and video recording of the screen**
|
||||
The following shortcuts can be used to print the screen or take a video recording of the screen.
|
||||
[![][5]][6]**Switching between applications**
|
||||
The shortcut keys listed here can be used to switch between applications.
|
||||
|
||||
[![][7]][8]
|
||||
**Tile windows**
|
||||
The windows can be tiled in different ways using the shortcuts given below.
|
||||
|
||||
[![][9]][10]
|
||||
|
||||
**Browser shortcuts**
|
||||
The most frequently used shortcuts for browsers are listed here. Most of the shortcuts are common to the Chrome/Firefox browsers.
|
||||
|
||||
**Key combination** | **Action**
|
||||
---|---
|
||||
Ctrl + T | Opens a new tab.
|
||||
Ctrl + Shift + T | Opens the most recently closed tab.
|
||||
Ctrl + D | Adds a new bookmark.
|
||||
Ctrl + W | Closes the browser tab.
|
||||
Alt + D | Positions the cursor in the browser’s address bar.
|
||||
F5 or Ctrl-R | Refreshes a page.
|
||||
Ctrl + Shift + Del | Clears private data and history.
|
||||
Ctrl + N | Opens a new window.
|
||||
Home | Scrolls to the top of the page.
|
||||
End | Scrolls to the bottom of the page.
|
||||
Ctrl + J | Opens the Downloads folder
|
||||
(in Chrome)
|
||||
F11 | Full-screen view (toggle effect)
|
||||
|
||||
**Terminal shortcuts**
|
||||
Here is a list of terminal shortcuts.
|
||||
[![][11]][12]You can also configure your own custom shortcuts in Ubuntu, as follows:
|
||||
|
||||
* Click on Settings in Ubuntu Dash.
|
||||
* Select the Devices tab in the left menu of the Settings window.
|
||||
* Select the Keyboard tab in the Devices menu.
|
||||
* The ‘+’ button is displayed at the bottom of the right panel. Click on the ‘+’ sign to open the custom shortcut dialogue box and configure a new shortcut.
|
||||
|
||||
|
||||
|
||||
Learning three shortcuts mentioned in this article can save a lot of time and make you more productive.
|
||||
|
||||
**Reference**
|
||||
_Cohen, Andrew. How keyboard shortcuts could revive America’s economy; [www.brainscape.com][13]. [Online] Brainscape, 26 May 2017; <https://www.brainscape.com/blog/2011/08/keyboard-shortcuts-economy/>_
|
||||
|
||||
![Avatar][14]
|
||||
|
||||
[S Sathyanarayanan][15]
|
||||
|
||||
The author is currently working with Sri Sathya Sai University for Human Excellence, Gulbarga. He has more than 25 years of experience in systems management and in teaching IT courses. He is an enthusiastic promoter of FOSS and can be reached at [sathyanarayanan.brn@gmail.com][16].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensourceforu.com/2019/11/keyboard-shortcuts-to-speed-up-your-work-in-linux/
|
||||
|
||||
作者:[S Sathyanarayanan][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://opensourceforu.com/author/s-sathyanarayanan/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2016/12/Google-Keyboard.jpg?resize=696%2C418&ssl=1 (Google Keyboard)
|
||||
[2]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2016/12/Google-Keyboard.jpg?fit=750%2C450&ssl=1
|
||||
[3]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/1.png?resize=350%2C319&ssl=1
|
||||
[4]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/1.png?ssl=1
|
||||
[5]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/NW.png?resize=350%2C326&ssl=1
|
||||
[6]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/NW.png?ssl=1
|
||||
[7]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/2.png?resize=350%2C264&ssl=1
|
||||
[8]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/2.png?ssl=1
|
||||
[9]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/3.png?resize=350%2C186&ssl=1
|
||||
[10]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/3.png?ssl=1
|
||||
[11]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/7.png?resize=350%2C250&ssl=1
|
||||
[12]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/7.png?ssl=1
|
||||
[13]: http://www.brainscape.com
|
||||
[14]: https://secure.gravatar.com/avatar/736684a2707f2ed7ae72675edf7bb3ee?s=100&r=g
|
||||
[15]: https://opensourceforu.com/author/s-sathyanarayanan/
|
||||
[16]: mailto:sathyanarayanan.brn@gmail.com
|
@ -0,0 +1,434 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (An introduction to monitoring with Prometheus)
|
||||
[#]: via: (https://opensource.com/article/19/11/introduction-monitoring-prometheus)
|
||||
[#]: author: (Yuri Grinshteyn https://opensource.com/users/yuri-grinshteyn)
|
||||
|
||||
An introduction to monitoring with Prometheus
|
||||
======
|
||||
Prometheus is a popular and powerful toolkit to monitor Kubernetes. This
|
||||
is a tutorial on how to get started.
|
||||
![Wheel of a ship][1]
|
||||
|
||||
[Metrics are the primary way][2] to represent both the overall health of your system and any other specific information you consider important for monitoring and alerting or observability. [Prometheus][3] is a leading open source metric instrumentation, collection, and storage toolkit [built at SoundCloud][4] beginning in 2012. Since then, it's [graduated][5] from the Cloud Native Computing Foundation and become the de facto standard for Kubernetes monitoring. It has been covered in some detail in:
|
||||
|
||||
* [Getting started with Prometheus][6]
|
||||
* [5 examples of Prometheus monitoring success][7]
|
||||
* [Achieve high-scale application monitoring with Prometheus][8]
|
||||
* [Tracking the weather with Python and Prometheus][9]
|
||||
|
||||
|
||||
|
||||
However, none of these articles focus on how to use Prometheus on Kubernetes. This article:
|
||||
|
||||
* Describes the Prometheus architecture and data model to help you understand how it works and what it can do
|
||||
* Provides a tutorial on setting Prometheus up in a Kubernetes cluster and using it to monitor clusters and applications
|
||||
|
||||
|
||||
|
||||
### Architecture
|
||||
|
||||
While knowing how Prometheus works may not be essential to using it effectively, it can be helpful, especially if you're considering using it for production. The [Prometheus documentation][10] provides this graphic and details about the essential elements of Prometheus and how the pieces connect together.
|
||||
|
||||
[![Prometheus architecture][11]][10]
|
||||
|
||||
For most use cases, you should understand three major components of Prometheus:
|
||||
|
||||
1. The Prometheus **server** scrapes and stores metrics. Note that it uses a **persistence** layer, which is part of the server and not expressly mentioned in the documentation. Each node of the server is autonomous and does not rely on distributed storage. I'll revisit this later when looking to use a dedicated time-series database to store Prometheus data, rather than relying on the server itself.
|
||||
2. The web **UI** allows you to access, visualize, and chart the stored data. Prometheus provides its own UI, but you can also configure other visualization tools, like [Grafana][12], to access the Prometheus server using PromQL (the Prometheus Query Language).
|
||||
3. **Alertmanager** sends alerts from client applications, especially the Prometheus server. It has advanced features for deduplicating, grouping, and routing alerts and can route through other services like PagerDuty and OpsGenie.
|
||||
|
||||
|
||||
|
||||
The key to understanding Prometheus is that it fundamentally relies on **scraping**, or pulling, metrics from defined endpoints. This means that your application needs to expose an endpoint where metrics are available and instruct the Prometheus server how to scrape it (this is covered in the tutorial below). There are [exporters][13] for many applications that do not have an easy way to add web endpoints, such as [Kafka][14] and [Cassandra][15] (using the JMX exporter).
|
||||
|
||||
### Data model
|
||||
|
||||
Now that you understand how Prometheus works to scrape and store metrics, the next thing to learn is the kinds of metrics Prometheus supports. Some of the following information (noted with quotation marks) comes from the [metric types][16] section of the Prometheus documentation.
|
||||
|
||||
#### Counters and gauges
|
||||
|
||||
The two simplest metric types are **counter** and **gauge**. When getting started with Prometheus (or with time-series monitoring more generally), these are the easiest types to understand because it's easy to connect them to values you can imagine monitoring, like how much system resources your application is using or how many events it has processed.
|
||||
|
||||
> "A **counter** is a cumulative metric that represents a single monotonically increasing counter whose value can only **increase** or be **reset** to zero on restart. For example, you can use a counter to represent the number of requests served, tasks completed, or errors."
|
||||
|
||||
Because you cannot decrease a counter, it can and should be used only to represent cumulative metrics.
|
||||
|
||||
> "A **gauge** is a metric that represents a single numerical value that can arbitrarily go up and down. Gauges are typically used for measured values like [CPU] or current memory usage, but also 'counts' that can go up and down, like the number of concurrent requests."
|
||||
|
||||
#### Histograms and summaries
|
||||
|
||||
Prometheus supports two more complex metric types: [**histograms**][17] [and][17] [**summaries**][17]. There is ample opportunity for confusion here, given that they both track the number of observations _and_ the sum of observed values. One of the reasons you might choose to use them is that you need to calculate an average of the observed values. Note that they create multiple time series in the database; for example, they each create a sum of the observed values with a **_sum** suffix.
|
||||
|
||||
> "A **histogram** samples observations (usually things like request durations or response sizes) and counts them in configurable buckets. It also provides a sum of all observed values."
|
||||
|
||||
This makes it an excellent candidate to track things like latency that might have a service level objective (SLO) defined against it. From the [documentation][17]:
|
||||
|
||||
> You might have an SLO to serve 95% of requests within 300ms. In that case, configure a histogram to have a bucket with an upper limit of 0.3 seconds. You can then directly express the relative amount of requests served within 300ms and easily alert if the value drops below 0.95. The following expression calculates it by job for the requests served in the last 5 minutes. The request durations were collected with a histogram called **http_request_duration_seconds**.
|
||||
>
|
||||
> [code]`sum(rate(http_request_duration_seconds_bucket{le="0.3"}[5m])) by (job) / sum(rate(http_request_duration_seconds_count[5m])) by (job)`
|
||||
```
|
||||
>
|
||||
>
|
||||
|
||||
Returning to definitions:
|
||||
|
||||
> "Similar to a histogram, a **summary** samples observations (usually things like request durations and response sizes). While it also provides a total count of observations and a sum of all observed values, it calculates configurable quantiles over a sliding time window."
|
||||
|
||||
The essential difference between summaries and histograms is that summaries calculate streaming φ-quantiles on the client-side and expose them directly, while histograms expose bucketed observation counts, and the calculation of quantiles from the buckets of a histogram happens on the server-side using the **histogram_quantile()** function.
|
||||
|
||||
If you are still confused, I suggest taking the following approach:
|
||||
|
||||
* Use gauges most of the time for straightforward time-series metrics.
|
||||
* Use counters for things you know to increase monotonically, e.g., if you are counting the number of times something happens.
|
||||
* Use histograms for latency measurements with simple buckets, e.g., one bucket for "under SLO" and another for "over SLO."
|
||||
|
||||
|
||||
|
||||
This should be sufficient for the overwhelming majority of use cases, and you should rely on a statistical analysis expert to help you with more advanced scenarios.
|
||||
|
||||
Now that you have a basic understanding of what Prometheus is, how it works, and the kinds of data it can collect and store, you're ready to begin the tutorial.
|
||||
|
||||
## Prometheus and Kubernetes hands-on tutorial
|
||||
|
||||
This tutorial covers the following:
|
||||
|
||||
* Installing Prometheus in your cluster
|
||||
* Downloading the sample application and reviewing the code
|
||||
* Building and deploying the app and generating load against it
|
||||
* Accessing the Prometheus UI and reviewing the basic metrics
|
||||
|
||||
|
||||
|
||||
This tutorial assumes:
|
||||
|
||||
* You already have a Kubernetes cluster deployed.
|
||||
* You have configured the **kubectl** command-line utility for access.
|
||||
* You have the **cluster-admin** role (or at least sufficient privileges to create namespaces and deploy applications).
|
||||
* You are running a Bash-based command-line interface. Adjust this tutorial if you run other operating systems or shell environments.
|
||||
|
||||
|
||||
|
||||
If you don't have Kubernetes running yet, this [Minikube tutorial][18] is an easy way to set it up on your laptop.
|
||||
|
||||
If you're ready now, let's go.
|
||||
|
||||
### Install Prometheus
|
||||
|
||||
In this section, you will clone the sample repository and use Kubernetes' configuration files to deploy Prometheus to a dedicated namespace.
|
||||
|
||||
1. Clone the sample repository locally and use it as your working directory: [code] $ git clone <https://github.com/yuriatgoogle/prometheus-demo.git>
|
||||
$ cd prometheus-demo
|
||||
$ WORKDIR=$(pwd)
|
||||
```
|
||||
2. Create a dedicated namespace for the Prometheus deployment: [code]`$ kubectl create namespace prometheus`
|
||||
```
|
||||
3. Give your namespace the cluster reader role: [code] $ kubectl apply -f $WORKDIR/kubernetes/clusterRole.yaml
|
||||
clusterrole.rbac.authorization.k8s.io/prometheus created
|
||||
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
|
||||
```
|
||||
4. Create a Kubernetes configmap with scraping and alerting rules: [code] $ kubectl apply -f $WORKDIR/kubernetes/configMap.yaml -n prometheus
|
||||
configmap/prometheus-server-conf created
|
||||
```
|
||||
5. Deploy Prometheus: [code] $ kubectl create -f prometheus-deployment.yaml -n prometheus
|
||||
deployment.extensions/prometheus-deployment created
|
||||
```
|
||||
6. Validate that Prometheus is running: [code] $ kubectl get pods -n prometheus
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
prometheus-deployment-78fb5694b4-lmz4r 1/1 Running 0 15s
|
||||
```
|
||||
### Review basic metrics
|
||||
|
||||
In this section, you'll access the Prometheus UI and review the metrics being collected.
|
||||
|
||||
1. Use port forwarding to enable web access to the Prometheus UI locally:
|
||||
**Note:** Your **prometheus-deployment** will have a different name than this example. Review and replace the name of the pod from the output of the previous command. [code] $ kubectl port-forward prometheus-deployment-7ddb99dcb-fkz4d 8080:9090 -n prometheus
|
||||
Forwarding from 127.0.0.1:8080 -> 9090
|
||||
Forwarding from [::1]:8080 -> 9090
|
||||
```
|
||||
|
||||
2. Go to <http://localhost:8080> in a browser:
|
||||
![Prometheus console][19]
|
||||
|
||||
You are now ready to query Prometheus metrics!
|
||||
|
||||
|
||||
|
||||
3. Some basic machine metrics (like the number of CPU cores and memory) are available right away. For example, enter **machine_memory_bytes** in the expression field, switch to the Graph view, and click Execute to see the metric charted:
|
||||
|
||||
|
||||
|
||||
![Prometheus metric channel][20]
|
||||
|
||||
4. Containers running in the cluster are also automatically monitored. For example, enter **rate(container_cpu_usage_seconds_total{container_name="prometheus"}[1m])** as the expression and click Execute to see the rate of CPU usage by Prometheus:
|
||||
|
||||
|
||||
|
||||
![CPU usage metric][21]
|
||||
|
||||
Now that you know how to install Prometheus and use it to measure some out-of-the-box metrics, it's time for some real monitoring.
|
||||
|
||||
#### Golden signals
|
||||
|
||||
As described in the "[Monitoring Distributed Systems][22]" chapter of [Google's SRE][23] book:
|
||||
|
||||
> "The four golden signals of monitoring are latency, traffic, errors, and saturation. If you can only measure four metrics of your user-facing system, focus on these four."
|
||||
|
||||
The book offers thorough descriptions of all four, but this tutorial focuses on the three signals that most easily serve as proxies for user happiness:
|
||||
|
||||
* **Traffic:** How many requests you're receiving
|
||||
* **Error rate:** How many of those requests you can successfully serve
|
||||
* **Latency:** How quickly you can serve successful requests
|
||||
|
||||
|
||||
|
||||
As you probably realize by now, Prometheus does not measure any of these for you; you'll have to instrument any application you deploy to emit them. Following is an example implementation.
|
||||
|
||||
Open the **$WORKDIR/node/golden_signals/app.js** file, which is a sample application written in Node.js (recall we cloned **yuriatgoogle/prometheus-demo** and exported **$WORKDIR** earlier). Start by reviewing the first section, where the metrics to be recorded are defined:
|
||||
|
||||
|
||||
```
|
||||
// total requests - counter
|
||||
const nodeRequestsCounter = new prometheus.Counter({
|
||||
name: 'node_requests',
|
||||
help: 'total requests'
|
||||
});
|
||||
```
|
||||
|
||||
The first metric is a counter that will be incremented for each request; this is how the total number of requests is counted:
|
||||
|
||||
|
||||
```
|
||||
// failed requests - counter
|
||||
const nodeFailedRequestsCounter = new prometheus.Counter({
|
||||
name: 'node_failed_requests',
|
||||
help: 'failed requests'
|
||||
});
|
||||
```
|
||||
|
||||
The second metric is another counter that increments for each error to track the number of failed requests:
|
||||
|
||||
|
||||
```
|
||||
// latency - histogram
|
||||
const nodeLatenciesHistogram = new prometheus.Histogram({
|
||||
name: 'node_request_latency',
|
||||
help: 'request latency by path',
|
||||
labelNames: ['route'],
|
||||
buckets: [100, 400]
|
||||
});
|
||||
```
|
||||
|
||||
The third metric is a histogram that tracks request latency. Working with a very basic assumption that the SLO for latency is 100ms, you will create two buckets: one for 100ms and the other 400ms latency.
|
||||
|
||||
The next section handles incoming requests, increments the total requests metric for each one, increments failed requests when there is an (artificially induced) error, and records a latency histogram value for each successful request. I have chosen not to record latencies for errors; that implementation detail is up to you.
|
||||
|
||||
|
||||
```
|
||||
app.get('/', (req, res) => {
|
||||
// start latency timer
|
||||
const requestReceived = new Date().getTime();
|
||||
console.log('request made');
|
||||
// increment total requests counter
|
||||
nodeRequestsCounter.inc();
|
||||
// return an error 1% of the time
|
||||
if ((Math.floor(Math.random() * 100)) == 100) {
|
||||
// increment error counter
|
||||
nodeFailedRequestsCounter.inc();
|
||||
// return error code
|
||||
res.send("error!", 500);
|
||||
}
|
||||
else {
|
||||
// delay for a bit
|
||||
sleep.msleep((Math.floor(Math.random() * 1000)));
|
||||
// record response latency
|
||||
const responseLatency = new Date().getTime() - requestReceived;
|
||||
nodeLatenciesHistogram
|
||||
.labels(req.route.path)
|
||||
.observe(responseLatency);
|
||||
res.send("success in " + responseLatency + " ms");
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### Test locally
|
||||
|
||||
Now that you've seen how to implement Prometheus metrics, see what happens when you run the application.
|
||||
|
||||
1. Install the required packages: [code] $ cd $WORKDIR/node/golden_signals
|
||||
$ npm install --save
|
||||
```
|
||||
2. Launch the app: [code]`$ node app.js`
|
||||
```
|
||||
3. Open two browser tabs: one to <http://localhost:8080> and another to <http://localhost:8080/metrics>.
|
||||
4. When you go to the **/metrics** page, you can see the Prometheus metrics being collected and updated every time you reload the home page:
|
||||
|
||||
|
||||
|
||||
![Prometheus metrics being collected][24]
|
||||
|
||||
You're now ready to deploy the sample application to your Kubernetes cluster and test your monitoring.
|
||||
|
||||
#### Deploy monitoring to Prometheus on Kubernetes
|
||||
|
||||
Now it's time to see how metrics are recorded and represented in the Prometheus instance deployed in your cluster by:
|
||||
|
||||
* Building the application image
|
||||
* Deploying it to your cluster
|
||||
* Generating load against the app
|
||||
* Observing the metrics recorded
|
||||
|
||||
|
||||
|
||||
##### Build the application image
|
||||
|
||||
The sample application provides a Dockerfile you'll use to build the image. This section assumes that you have:
|
||||
|
||||
* Docker installed and configured locally
|
||||
* A Docker Hub account
|
||||
* Created a repository
|
||||
|
||||
|
||||
|
||||
If you're using Google Kubernetes Engine to run your cluster, you can use Cloud Build and the Google Container Registry instead.
|
||||
|
||||
1. Switch to the application directory: [code]`$ cd $WORKDIR/node/golden_signals`
|
||||
```
|
||||
2. Build the image with this command: [code]`$ docker build . --tag=<Docker username>/prometheus-demo-node:latest`
|
||||
```
|
||||
3. Make sure you're logged in to Docker Hub: [code]`$ docker login`
|
||||
```
|
||||
4. Push the image to Docker Hub using this command: [code]`$ docker push <username>/prometheus-demo-node:latest`
|
||||
```
|
||||
5. Verify that the image is available: [code]`$ docker images`
|
||||
```
|
||||
#### Deploy the application
|
||||
|
||||
Now that the application image is in the Docker Hub, you can deploy it to your cluster and run the application.
|
||||
|
||||
1. Modify the **$WORKDIR/node/golden_signals/prometheus-demo-node.yaml** file to pull the image from Docker Hub: [code] spec:
|
||||
containers:
|
||||
- image: docker.io/<Docker username>/prometheus-demo-node:latest
|
||||
```
|
||||
2. Deploy the image: [code] $ kubectl apply -f $WORKDIR/node/golden_signals/prometheus-demo-node.yaml
|
||||
deployment.extensions/prometheus-demo-node created
|
||||
```
|
||||
3. Verify that the application is running: [code] $ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
prometheus-demo-node-69688456d4-krqqr 1/1 Running 0 65s
|
||||
```
|
||||
4. Expose the application using a load balancer: [code] $ kubectl expose deployment prometheus-node-demo --type=LoadBalancer --name=prometheus-node-demo --port=8080
|
||||
service/prometheus-demo-node exposed
|
||||
```
|
||||
5. Confirm that your service has an external IP address: [code] $ kubectl get services
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
kubernetes ClusterIP 10.39.240.1 <none> 443/TCP 23h
|
||||
prometheus-demo-node LoadBalancer 10.39.248.129 35.199.186.110 8080:31743/TCP 78m
|
||||
```
|
||||
|
||||
|
||||
|
||||
##### Generate load to test monitoring
|
||||
|
||||
Now that your service is up and running, generate some load against it by using [Apache Bench][25].
|
||||
|
||||
1. Get the IP address of your service as a variable: [code]`$ export SERVICE_IP=$(kubectl get svc prometheus-demo-node -ojson | jq -r '.status.loadBalancer.ingress[].ip')`
|
||||
```
|
||||
2. Use **ab** to generate some load. You may want to run this in a separate terminal window. [code]`$ ab -c 3 -n 1000 http://${SERVICE_IP}:8080/`
|
||||
```
|
||||
|
||||
|
||||
|
||||
##### Review metrics
|
||||
|
||||
While the load is running, access the Prometheus UI in the cluster again and confirm that the "golden signal" metrics are being collected.
|
||||
|
||||
1. Establish a connection to Prometheus: [code]
|
||||
|
||||
$ kubectl get pods -n prometheus
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
prometheus-deployment-78fb5694b4-lmz4r 1/1 Running 0 15s
|
||||
|
||||
$ kubectl port-forward prometheus-deployment-78fb5694b4-lmz4r 8080:9090 -n prometheus
|
||||
Forwarding from 127.0.0.1:8080 -> 9090
|
||||
Forwarding from [::1]:8080 -> 9090
|
||||
|
||||
```
|
||||
**Note:** Make sure to replace the name of the pod in the second command with the output of the first.
|
||||
|
||||
2. Open <http://localhost:8080> in a browser:
|
||||
|
||||
|
||||
|
||||
|
||||
![Prometheus console][26]
|
||||
|
||||
3. Use this expression to measure the request rate: [code]`rate(node_requests[1m])`
|
||||
```
|
||||
|
||||
|
||||
|
||||
![Measuring the request rate][27]
|
||||
|
||||
4. Use this expression to measure your error rate: [code]`rate(node_failed_requests[1m])`
|
||||
```
|
||||
![Measuring the error rate][28]
|
||||
|
||||
5. Finally, use this expression to validate your latency SLO. Remember that you set up two buckets, 100ms and 400ms. This expression returns the percentage of requests that meet the SLO : [code]`sum(rate(node_request_latency_bucket{le="100"}[1h])) / sum(rate(node_request_latency_count[1h]))`
|
||||
```
|
||||
|
||||
|
||||
|
||||
![SLO query graph][29]
|
||||
|
||||
About 10% of the requests are within SLO. This is what you should expect since the code sleeps for a random number of milliseconds between 0 and 1,000. As such, about 10% of the time, it returns in more than 100ms, and this graph shows that you can't meet the latency SLO as a result.
|
||||
|
||||
### Summary
|
||||
|
||||
Congratulations! You've completed the tutorial and hopefully have a much better understanding of how Prometheus works, how to instrument your application with custom metrics, and how to use it to measure your SLO compliance. The next article in this series will look at another metric instrumentation approach using OpenCensus.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/introduction-monitoring-prometheus
|
||||
|
||||
作者:[Yuri Grinshteyn][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/yuri-grinshteyn
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/kubernetes.png?itok=PqDGb6W7 (Wheel of a ship)
|
||||
[2]: https://opensource.com/article/19/10/open-source-observability-kubernetes
|
||||
[3]: https://prometheus.io/
|
||||
[4]: https://en.wikipedia.org/wiki/Prometheus_(software)#History
|
||||
[5]: https://www.cncf.io/announcement/2018/08/09/prometheus-graduates/
|
||||
[6]: https://opensource.com/article/18/12/introduction-prometheus
|
||||
[7]: https://opensource.com/article/18/9/prometheus-operational-advantage
|
||||
[8]: https://opensource.com/article/19/10/application-monitoring-prometheus
|
||||
[9]: https://opensource.com/article/19/4/weather-python-prometheus
|
||||
[10]: https://prometheus.io/docs/introduction/overview/
|
||||
[11]: https://opensource.com/sites/default/files/uploads/prometheus-architecture.png (Prometheus architecture)
|
||||
[12]: https://grafana.com/
|
||||
[13]: https://prometheus.io/docs/instrumenting/exporters/
|
||||
[14]: https://github.com/danielqsj/kafka_exporter
|
||||
[15]: https://github.com/prometheus/jmx_exporter
|
||||
[16]: https://prometheus.io/docs/concepts/metric_types/
|
||||
[17]: https://prometheus.io/docs/practices/histograms/
|
||||
[18]: https://opensource.com/article/18/10/getting-started-minikube
|
||||
[19]: https://opensource.com/sites/default/files/uploads/prometheus-console.png (Prometheus console)
|
||||
[20]: https://opensource.com/sites/default/files/uploads/prometheus-machine_memory_bytes.png (Prometheus metric channel)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/prometheus-cpu-usage.png (CPU usage metric)
|
||||
[22]: https://landing.google.com/sre/sre-book/chapters/monitoring-distributed-systems/
|
||||
[23]: https://landing.google.com/sre/sre-book/toc/
|
||||
[24]: https://opensource.com/sites/default/files/uploads/prometheus-metrics-collected.png (Prometheus metrics being collected)
|
||||
[25]: https://httpd.apache.org/docs/2.4/programs/ab.html
|
||||
[26]: https://opensource.com/sites/default/files/uploads/prometheus-enable-query-history.png (Prometheus console)
|
||||
[27]: https://opensource.com/sites/default/files/uploads/prometheus-request-rate.png (Measuring the request rate)
|
||||
[28]: https://opensource.com/sites/default/files/uploads/prometheus-error-rate.png (Measuring the error rate)
|
||||
[29]: https://opensource.com/sites/default/files/uploads/prometheus-slo-query.png (SLO query graph)
|
@ -0,0 +1,241 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Schedule and Automate tasks in Linux using Cron Jobs)
|
||||
[#]: via: (https://www.linuxtechi.com/schedule-automate-tasks-linux-cron-jobs/)
|
||||
[#]: author: (Pradeep Kumar https://www.linuxtechi.com/author/pradeep/)
|
||||
|
||||
How to Schedule and Automate tasks in Linux using Cron Jobs
|
||||
======
|
||||
|
||||
Sometimes, you may have tasks that need to be performed on a regular basis or at certain predefined intervals. Such tasks include backing up databases, updating the system, performing periodic reboots and so on. Such tasks are referred to as **cron jobs**. Cron jobs are used for **automation of tasks** that come in handy and help in simplifying the execution of repetitive and sometimes mundane tasks. **Cron** is a daemon that allows you to schedule these jobs which are then carried out at specified intervals. In this tutorial, you will learn how to schedule jobs using cron jobs.
|
||||
|
||||
[![Schedule -tasks-in-Linux-using cron][1]][2]
|
||||
|
||||
### The Crontab file
|
||||
|
||||
A crontab file, also known as a **cron table**, is a simple text file that contains rules or commands that specify the time interval of execution of a task. There are two categories of crontab files:
|
||||
|
||||
**1) System-wide crontab file**
|
||||
|
||||
These are usually used by Linux services & critical applications requiring root privileges. The system crontab file is located at **/etc/crontab** and can only be accessed and edited by the root user. It’s usually used for the configuration of system-wide daemons. The crontab file looks as shown:
|
||||
|
||||
[![etc-crontab-linux][1]][3]
|
||||
|
||||
**2) User-created crontab files**
|
||||
|
||||
Linux users can also create their own cron jobs with the help of the crontab command. The cron jobs created will run as the user who created them.
|
||||
|
||||
All cron jobs are stored in /var/spool/cron (For RHEL and CentOS distros) and /var/spool/cron/crontabs (For Debian and Ubuntu distros), the cron jobs are listed using the username of the user that created the cron job
|
||||
|
||||
The **cron daemon** runs silently in the background checking the **/etc/crontab** file and **/var/spool/cron** and **/etc/cron.d*/** directories
|
||||
|
||||
The **crontab** command is used for editing cron files. Let us take a look at the anatomy of a crontab file.
|
||||
|
||||
### The anatomy of a crontab file
|
||||
|
||||
Before we go further, it’s important that we first explore how a crontab file looks like. The basic syntax for a crontab file comprises 5 columns represented by asterisks followed by the command to be carried out.
|
||||
|
||||
* * * * * command
|
||||
|
||||
This format can also be represented as shown below:
|
||||
|
||||
m h d moy dow command
|
||||
|
||||
OR
|
||||
|
||||
m h d moy dow /path/to/script
|
||||
|
||||
Let’s expound on each entry
|
||||
|
||||
* **m**: This represents minutes. It’s specified from 0 to 59
|
||||
* **h**: This denoted the hour specified from 0 to 23
|
||||
* **d**: This represents the day of the month. Specified between 1 to 31`
|
||||
* **moy**: This is the month of the year. It’s specified between 1 to 12
|
||||
* **doy**: This is the day of the week. It’s specified between 0 and 6 where 0 = Sunday
|
||||
* **Command**: This is the command to be executed e.g backup command, reboot, & copy
|
||||
|
||||
|
||||
|
||||
### Managing cron jobs
|
||||
|
||||
Having looked at the architecture of a crontab file, let’s see how you can create, edit and delete cron jobs
|
||||
|
||||
**Creating cron jobs**
|
||||
|
||||
To create or edit a cron job as the root user, run the command
|
||||
|
||||
# crontab -e
|
||||
|
||||
To create a cron job or schedule a task as another user, use the syntax
|
||||
|
||||
# crontab -u username -e
|
||||
|
||||
For instance, to run a cron job as user Pradeep, issue the command:
|
||||
|
||||
# crontab -u Pradeep -e
|
||||
|
||||
If there is no preexisting crontab file, then you will get a blank text document. If a crontab file was existing, The -e option allows to edit the file,
|
||||
|
||||
**Listing crontab files**
|
||||
|
||||
To view the cron jobs that have been created, simply pass the -l option as shown
|
||||
|
||||
# crontab -l
|
||||
|
||||
**Deleting a crontab file**
|
||||
|
||||
To delete a cron file, simply run crontab -e and delete or the line of the cron job that you want and save the file.
|
||||
|
||||
To remove all cron jobs, run the command:
|
||||
|
||||
# crontab -r
|
||||
|
||||
That said, let’s have a look at different ways that you can schedule tasks
|
||||
|
||||
### Crontab examples in Scheduling tasks.
|
||||
|
||||
All cron jobs being with a shebang header as shown
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
This indicates the shell you are using, which, for this case, is bash shell.
|
||||
|
||||
Next, specify the interval at which you want to schedule the tasks using the cron job entries we specified earlier on.
|
||||
|
||||
To reboot a system daily at 12:30 pm, use the syntax:
|
||||
|
||||
30 12 * * * /sbin/reboot
|
||||
|
||||
To schedule the reboot at 4:00 am use the syntax:
|
||||
|
||||
0 4 * * * /sbin/reboot
|
||||
|
||||
**NOTE:** The asterisk * is used to match all records
|
||||
|
||||
To run a script twice every day, for example, 4:00 am and 4:00 pm, use the syntax.
|
||||
|
||||
0 4,16 * * * /path/to/script
|
||||
|
||||
To schedule a cron job to run every Friday at 5:00 pm use the syntax:
|
||||
|
||||
0 17 * * Fri /path/to/script
|
||||
|
||||
OR
|
||||
|
||||
0 17 * * * 5 /path/to/script
|
||||
|
||||
If you wish to run your cron job every 30 minutes then use:
|
||||
|
||||
*/30 * * * * /path/to/script
|
||||
|
||||
To schedule cron to run after every 5 hours, run
|
||||
|
||||
* */5 * * * /path/to/script
|
||||
|
||||
To run a script on selected days, for example, Wednesday and Friday at 6.00 pm execute:
|
||||
|
||||
0 18 * * wed,fri /path/to/script
|
||||
|
||||
To schedule multiple tasks to use a single cron job, separate the tasks using a semicolon for example:
|
||||
|
||||
* * * * * /path/to/script1 ; /path/to/script2
|
||||
|
||||
### Using special strings to save time on writing cron jobs
|
||||
|
||||
Some of the cron jobs can easily be configured using special strings that correspond to certain time intervals. For example,
|
||||
|
||||
1) @hourly timestamp corresponds to 0 * * * *
|
||||
|
||||
It will execute a task in the first minute of every hour.
|
||||
|
||||
@hourly /path/to/script
|
||||
|
||||
2) @daily timestamp is equivalent to 0 0 * * *
|
||||
|
||||
It executes a task in the first minute of every day (midnight). It comes in handy when executing daily jobs.
|
||||
|
||||
@daily /path/to/script
|
||||
|
||||
3) @weekly timestamp is the equivalent to 0 0 1 * mon
|
||||
|
||||
It executes a cron job in the first minute of every week where a week whereby, a week starts on Monday.
|
||||
|
||||
@weekly /path/to/script
|
||||
|
||||
3) @monthly is similar to the entry 0 0 1 * *
|
||||
|
||||
It carries out a task in the first minute of the first day of the month.
|
||||
|
||||
@monthly /path/to/script
|
||||
|
||||
4) @yearly corresponds to 0 0 1 1 *
|
||||
|
||||
It executes a task in the first minute of every year and is useful in sending New year greetings 🙂
|
||||
|
||||
@monthly /path/to/script
|
||||
|
||||
### Crontab Restrictions
|
||||
|
||||
As a Linux user, you can control who has the right to use the crontab command. This is possible using the **/etc/cron.deny** and **/etc/cron.allow** file. By default, only the /etc/cron.deny file exists and does not contain any entries. To restrict a user from using the crontab utility, simply add a user’s username to the file. When a user is added to this file, and the user tries to run the crontab command, he/she will encounter the error below.
|
||||
|
||||
![restricted-cron-user][1]
|
||||
|
||||
To allow the user to continue using the crontab utility, simply remove the username from the /etc/cron.deny file.
|
||||
|
||||
If /etc/cron.allow file is present, then only the users listed in the file can access and use the crontab utility.
|
||||
|
||||
If neither file exists, then only the root user will have privileges to use the crontab command.
|
||||
|
||||
### Backing up crontab entries
|
||||
|
||||
It’s always advised to backup your crontab entries. To do so, use the syntax
|
||||
|
||||
# crontab -l > /path/to/file.txt
|
||||
|
||||
For example,
|
||||
|
||||
```
|
||||
# crontab -l > /home/james/backup.txt
|
||||
```
|
||||
|
||||
**Checking cron logs**
|
||||
|
||||
Cron logs are stored in /var/log/cron file. To view the cron logs run the command:
|
||||
|
||||
```
|
||||
# cat /var/log/cron
|
||||
```
|
||||
|
||||
![view-cron-log-files-linux][1]
|
||||
|
||||
To view live logs, use the tail command as shown:
|
||||
|
||||
```
|
||||
# tail -f /var/log/cron
|
||||
```
|
||||
|
||||
![view-live-cron-logs][1]
|
||||
|
||||
**Conclusion**
|
||||
|
||||
In this guide, you learned how to create cron jobs to automate repetitive tasks, how to backup as well as how to view cron logs. We hope that this article provided useful insights with regard to cron jobs. Please don’t hesitate to share your feedback and comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxtechi.com/schedule-automate-tasks-linux-cron-jobs/
|
||||
|
||||
作者:[Pradeep Kumar][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.linuxtechi.com/author/pradeep/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]: https://www.linuxtechi.com/wp-content/uploads/2019/11/Schedule-tasks-in-Linux-using-cron.jpg
|
||||
[3]: https://www.linuxtechi.com/wp-content/uploads/2019/11/etc-crontab-linux.png
|
@ -0,0 +1,50 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (My first contribution to open source: Make a fork of the repo)
|
||||
[#]: via: (https://opensource.com/article/19/11/first-open-source-contribution-fork-clone)
|
||||
[#]: author: (Galen Corey https://opensource.com/users/galenemco)
|
||||
|
||||
My first contribution to open source: Make a fork of the repo
|
||||
======
|
||||
Which comes first, to clone or fork a repo?
|
||||
![User experience vs. design][1]
|
||||
|
||||
Previously, I explained [how I ultimately chose a project][2] for my contributions. Once I finally picked that project and a task to work on, I felt like the hard part was over, and I slid into cruise control. I knew what to do next, no question. Just clone the repository so that I have the code on my computer, make a new branch for my work, and get coding, right?
|
||||
|
||||
It turns out I made a crucial mistake at this step. Unfortunately, I didn’t realize that I had made a mistake until several hours later when I tried to push my completed code back up to GitHub and got a permission denied error. My third mistake was trying to work directly from a clone of the repo.
|
||||
|
||||
When you want to contribute to someone else’s repo, in most cases, you should not clone the repo directly. Instead, you should make a fork of the repo and clone that. You do all of your work on a branch of your fork. Then, when you are ready to make a pull request, you can compare your branch on the fork against the master branch of the original repo.
|
||||
|
||||
Before this, I had only ever worked on repos that I either created or had collaborator permissions for, so I could work directly from a clone of the main repo. I did not realize that GitHub even offered the capability to make a pull request from a repo fork onto the original repo. Now that I’ve learned a bit about this option, it is a great feature that makes sense. Forking allows a project to open the ability to contribute to anyone with a GitHub account without having to add them all as "contributors." It also helps keep the main project clean by keeping most new branches on forks, so that they don’t create clutter.
|
||||
|
||||
I would have preferred to know this before I started writing my code (or, in this case, finished writing my code, since I didn’t attempt to push any of my changes to GitHub until the end). Moving my changes over from the main repo that I originally worked on into the fork was non-trivial.
|
||||
|
||||
For those of you getting started, here are the steps to make a PR on a repository that you do not own, or where you are not a collaborator. I highly recommend trying to push your code to GitHub and at least going through the steps of creating a PR before you get too deep into coding, just to make sure you have everything set up the right way:
|
||||
|
||||
1. Make a fork of the repo you’ve chosen for your contributions.
|
||||
2. From the fork, click **Clone or download** to create a copy on your computer.
|
||||
**Optional:** [Add the base repository as a remote "upstream,"][3] which is helpful if you want to pull down new changes from the base repository into your fork.
|
||||
3. [Create a pull request from the branch on your fork into the master branch of the base repository.][4]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/first-open-source-contribution-fork-clone
|
||||
|
||||
作者:[Galen Corey][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/galenemco
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/LIFE_DesirePath.png?itok=N_zLVWlK (User experience vs. design)
|
||||
[2]: https://opensource.com/article/19/10/first-open-source-contribution-mistake-two
|
||||
[3]: https://help.github.com/en/articles/configuring-a-remote-for-a-fork
|
||||
[4]: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork
|
322
translated/tech/20190801 Linux permissions 101.md
Normal file
322
translated/tech/20190801 Linux permissions 101.md
Normal file
@ -0,0 +1,322 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Linux permissions 101)
|
||||
[#]: via: (https://opensource.com/article/19/8/linux-permissions-101)
|
||||
[#]: author: (Alex Juarez https://opensource.com/users/mralexjuarezhttps://opensource.com/users/marcobravohttps://opensource.com/users/greg-p)
|
||||
|
||||
全面介绍 Linux 权限
|
||||
======
|
||||
|
||||
> 知道如何控制用户对文件的访问是一项基本的系统管理技能。
|
||||
|
||||
![Penguins][1]
|
||||
|
||||
了解 Linux 权限以及如何控制哪些用户可以访问文件是系统管理的一项基本技能。
|
||||
|
||||
本文将介绍标准 Linux 文件系统权限,并进一步研究特殊权限,以及使用 `umask` 解释默认权限的出处。
|
||||
|
||||
### 理解 ls 命令的输出
|
||||
|
||||
在讨论如何修改权限之前,我们需要知道如何查看权限。通过 `ls` 命令的长列表参数(`-l`)为我们提供了有关文件的许多信息。
|
||||
|
||||
```
|
||||
$ ls -lAh
|
||||
total 20K
|
||||
-rwxr-xr--+ 1 root root 0 Mar 4 19:39 file1
|
||||
-rw-rw-rw-. 1 root root 0 Mar 4 19:39 file10
|
||||
-rwxrwxr--+ 1 root root 0 Mar 4 19:39 file2
|
||||
-rw-rw-rw-. 1 root root 0 Mar 4 19:39 file8
|
||||
-rw-rw-rw-. 1 root root 0 Mar 4 19:39 file9
|
||||
drwxrwxrwx. 2 root root 4.0K Mar 4 20:04 testdir
|
||||
```
|
||||
|
||||
为了理解这些是什么意思,让我们将关于权限的输出分解为各个部分。单独理解每个部分会更容易。
|
||||
|
||||
让我们看看在上面的输出中的最后一行的每个组件:
|
||||
|
||||
```
|
||||
drwxrwxrwx. 2 root root 4.0K Mar 4 20:04 testdir
|
||||
```
|
||||
|
||||
第 1 节 | 第 2 节 | 第 3 节 | 第 4 节 | 第 5 节 | 第 6 节 | 第 7 节
|
||||
---|---|---|---|---|---|---
|
||||
`d` | `rwx` | `rwx` | `rwx` | `.` | `root` | `root`
|
||||
|
||||
第 1 节(左侧)显示文件的类型。
|
||||
|
||||
符号 | 类型
|
||||
---|---
|
||||
`d` | 目录
|
||||
`-` | 常规文件
|
||||
`l` | 软链接
|
||||
|
||||
`ls` 的 [info 页面][2]完整列出了不同的文件类型。
|
||||
|
||||
每个文件都有三种访问方式:
|
||||
|
||||
* 属主
|
||||
* 组
|
||||
* 所有其他人
|
||||
|
||||
第 2、3 和 4 节涉及用户、组和“其他用户”权限。每个部分都可以包含 `r`(读)、`w`(写)和 `x`(可执行)权限的组合。
|
||||
|
||||
每个权限还分配了一个数值,这在以八进制表示形式讨论权限时很重要。
|
||||
|
||||
权限 | 八进制值
|
||||
---|---
|
||||
`r` | 4
|
||||
`w` | 2
|
||||
`x` | 1
|
||||
|
||||
第 5 节描述了其他访问方法,例如 SELinux 或文件访问控制列表(FACL)。
|
||||
|
||||
访问方法 | 字符
|
||||
---|---
|
||||
没有其它访问方法 | `-`
|
||||
SELinux | `.`
|
||||
FACL | `+`
|
||||
各种方法的组合 | `+`
|
||||
|
||||
第 6 节和第 7 节分别是属主和组的名称。
|
||||
|
||||
### 使用 chown 和 chmod
|
||||
|
||||
#### chown 命令
|
||||
|
||||
`chown`(更改所有权)命令用于更改文件的用户和组的所有权。
|
||||
|
||||
要将文件 `foo` 的用户和组的所有权更改为 `root`,我们可以使用以下命令:
|
||||
|
||||
```
|
||||
$ chown root:root foo
|
||||
$ chown root: foo
|
||||
```
|
||||
|
||||
在用户后跟冒号(`:`)运行该命令将同时设置用户和组所有权。
|
||||
|
||||
要仅将文件 `foo` 的用户所有权设置为 `root` 用户,请输入:
|
||||
|
||||
```
|
||||
$ chown root foo
|
||||
```
|
||||
|
||||
要仅更改文件 `foo` 的组所有权,请在组之前加冒号:
|
||||
|
||||
```
|
||||
$ chown :root foo
|
||||
```
|
||||
|
||||
#### chmod 命令
|
||||
|
||||
`chmod`(更改模式)命令控制属主、组以及既不是属主也不属于与文件关联的组的所有其他用户的文件许可权。
|
||||
|
||||
`chmod` 命令可以以八进制(例如 `755`、`644` 等)和符号(例如 `u+rwx`、`g-rwx`、`o=rw`)格式设置权限。
|
||||
|
||||
八进制表示法将 4 个“点”分配给“读取”,将 2 个“点”分配给“写入”,将 1 个点分配给“执行”。如果要给用户(属主)分配“读”权限,则将 4 分配给第一个插槽,但是如果要添加“写”权限,则必须添加 2。如果要添加“执行”,则要添加 1。我们对每种权限类型执行此操作:属主、组和其他。
|
||||
|
||||
例如,如果我们想将 “读取”、“写入”和“执行”分配给文件的属主,但仅将“读取”和“执行”分配给组成员和所有其他用户,则我们应使用 `755`(八进制格式)。这是属主的所有权限位(`4 + 2 + 1`),但组和其他权限的所有权限位只有 `4` 和 `1`(`4 + 1`)。
|
||||
|
||||
> 细分为:4+2+1=7,4+1=5 和 4+1=5。
|
||||
|
||||
如果我们想将“读取”和“写入”分配给文件的属主,而只将“读取”分配给组的成员和所有其他用户,则可以如下使用 `chmod`:
|
||||
|
||||
```
|
||||
$ chmod 644 foo_file
|
||||
```
|
||||
|
||||
在下面的示例中,我们在不同的分组中使用符号表示法。注意字母 `u`、`g` 和 `o` 分别代表“用户”(属主)、“组”和“其他”。我们将 `u`、`g` 和 `o` 与 `+`、`-` 或 `=` 结合使用来添加、删除或设置权限位。
|
||||
|
||||
要将“执行”位添加到所有权权限集中:
|
||||
|
||||
```
|
||||
$ chmod u+x foo_file
|
||||
```
|
||||
|
||||
要从组成员中删除“读取”、“写入”和“执行”:
|
||||
|
||||
```
|
||||
$ chmod g-rwx foo_file
|
||||
```
|
||||
|
||||
要将所有其他用户的所有权设置为“读取”和“写入”:
|
||||
|
||||
```
|
||||
$ chmod o=rw
|
||||
```
|
||||
|
||||
### 特殊位:设置 UID、设置 GID 和粘滞位
|
||||
|
||||
除了标准权限外,还有一些特殊的权限位,它们具有一些有用的好处。
|
||||
|
||||
#### 设置用户 ID(suid)
|
||||
|
||||
当在文件上设置 `suid` 时,将以文件的属主的身份而不是运行该文件的用户身份执行操作。一个[好例子][3]是 `passwd` 命令。它需要设置 `suid` 位,以便更改密码的操作具有 root 权限。
|
||||
|
||||
```
|
||||
$ ls -l /bin/passwd
|
||||
-rwsr-xr-x. 1 root root 27832 Jun 10 2014 /bin/passwd
|
||||
```
|
||||
|
||||
设置 `suid` 位的示例:
|
||||
|
||||
```
|
||||
$ chmod u+s /bin/foo_file_name
|
||||
```
|
||||
|
||||
#### 设置组 ID(sgid)
|
||||
|
||||
`sgid` 位与 `suid` 位类似,因为操作是在目录的组所有权下完成的,而不是以运行命令的用户身份。
|
||||
|
||||
一个使用 `sgid` 的例子是,如果多个用户正在同一个目录中工作,并且目录中创建的每个文件都需要具有相同的组权限。下面的示例创建一个名为 `collab_dir` 的目录,设置 `sgid` 位,并将组所有权更改为 `webdev`。
|
||||
|
||||
```
|
||||
$ mkdir collab_dir
|
||||
$ chmod g+s collab_dir
|
||||
$ chown :webdev collab_dir
|
||||
```
|
||||
|
||||
现在,在该目录中创建的任何文件都将具有 `webdev` 的组所有权,而不是创建该文件的用户的组。
|
||||
|
||||
```
|
||||
$ cd collab_dir
|
||||
$ touch file-sgid
|
||||
$ ls -lah file-sgid
|
||||
-rw-r--r--. 1 root webdev 0 Jun 12 06:04 file-sgid
|
||||
```
|
||||
|
||||
#### “粘滞”位
|
||||
|
||||
粘滞位表示只有文件所有者才能删除该文件,即使组权限也允许该文件可以删除。通常,在 `/tmp` 这样的通用或协作目录上,此设置最有意义。在下面的示例中,“所有其他人”权限集的“执行”列中的 `t` 表示已应用粘滞位。
|
||||
|
||||
```
|
||||
$ ls -ld /tmp
|
||||
drwxrwxrwt. 8 root root 4096 Jun 12 06:07 /tmp/
|
||||
```
|
||||
|
||||
请记住,这不会阻止某个人编辑该文件,它只是阻止他们删除该目录的内容。
|
||||
|
||||
我们将粘滞位设置为:
|
||||
|
||||
```
|
||||
$ chmod o+t foo_dir
|
||||
```
|
||||
|
||||
你可以自己尝试在目录上设置粘滞位并赋予其完整的组权限,以便多个属于同一组的用户可以在目录上进行读取、写入和执行。
|
||||
|
||||
接着,以每个用户的身份创建文件,然后尝试以另一个用户的身份删除它们。
|
||||
|
||||
如果一切配置正确,则一个用户应该不能从另一用户那里删除文件。
|
||||
|
||||
请注意,这些位中的每个位也可以用八进制格式设置:SUID = 4、SGID = 2 和 粘滞位 = 1。(LCTT 译注:这里是四位八进制数字)
|
||||
|
||||
```
|
||||
$ chmod 4744
|
||||
$ chmod 2644
|
||||
$ chmod 1755
|
||||
```
|
||||
|
||||
#### 大写还是小写?
|
||||
|
||||
如果要设置特殊位并看到大写的 `S` 或 `T` 而不是小写的字符(如我们之前所见),那是因为不存在(对应的)底层的执行位。为了说明这一点,下面的示例创建一个设置了粘滞位的文件。然后,我们可以添加和删除执行位以演示大小写更改。
|
||||
|
||||
```
|
||||
$ touch file cap-ST-demo
|
||||
$ chmod 1755 cap-ST-demo
|
||||
$ ls -l cap-ST-demo
|
||||
-rwxr-xr-t. 1 root root 0 Jun 12 06:16 cap-ST-demo
|
||||
|
||||
$ chmod o-x cap-X-demo
|
||||
$ ls -l cap-X-demo
|
||||
-rwxr-xr-T. 1 root root 0 Jun 12 06:16 cap-ST-demo
|
||||
```
|
||||
|
||||
#### 有条件地设置执行位
|
||||
|
||||
至此,我们使用小写的 `x` 设置了执行位,而无需询问任何问题即可对其进行设置。我们还有另一种选择:使用大写的 `X` 而不是小写的,它将仅在权限组中某个位置已经有执行位时才设置执行位。这可能是一个很难解释的概念,但是下面的演示将帮助说明它。请注意,在尝试将执行位添加到组特权之后,该位没有被设置上。
|
||||
|
||||
```
|
||||
$ touch cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r--r--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
$ chmod g+X cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r--r--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
```
|
||||
|
||||
在这个类似的例子中,我们首先使用小写的 `x` 将执行位添加到组权限,然后使用大写的 `X` 为所有其他用户添加权限。这次,大写的 `X`设置了该权限。
|
||||
|
||||
```
|
||||
$ touch cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r--r--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
$ chmod g+x cap-X-file
|
||||
$ ls -l cap-X-file
|
||||
-rw-r-xr--. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
$ chmod o+X cap-X-file
|
||||
ls -l cap-X-file
|
||||
-rw-r-xr-x. 1 root root 0 Jun 12 06:31 cap-X-file
|
||||
```
|
||||
|
||||
### 理解 umask
|
||||
|
||||
`umask 会屏蔽(或“阻止”)默认权限集中的位,以定义文件或目录的权限。例如,`umask`输出中的 `2` 表示它至少在默认情况下阻止了文件的写入位。
|
||||
|
||||
使用不带任何参数的 `umask` 命令可以使我们看到当前的 `umask` 设置。共有四列:第一列为特殊的`suid`、`sgid` 或粘滞位而保留,其余三列代表属主、组和其他人的权限。
|
||||
|
||||
```
|
||||
$ umask
|
||||
0022
|
||||
```
|
||||
|
||||
为了理解这意味着什么,我们可以用 `-S` 标志来执行 `umask`(如下所示)以了解屏蔽位的结果。例如,由于第三列中的值为 `2`,因此将“写入”位从组和其他部分中屏蔽掉了;只能为它们分配“读取”和“执行”。
|
||||
|
||||
```
|
||||
$ umask -S
|
||||
u=rwx,g=rx,o=rx
|
||||
```
|
||||
|
||||
要查看文件和目录的默认权限集是什么,让我们将 `umask` 设置为全零。这意味着我们在创建文件时不会掩盖任何位。
|
||||
|
||||
```
|
||||
$ umask 000
|
||||
$ umask -S
|
||||
u=rwx,g=rwx,o=rwx
|
||||
|
||||
$ touch file-umask-000
|
||||
$ ls -l file-umask-000
|
||||
-rw-rw-rw-. 1 root root 0 Jul 17 22:03 file-umask-000
|
||||
```
|
||||
|
||||
现在,当我们创建文件时,我们看到所有部分的默认权限分别为“读取”(`4`)和“写入”(`2`),相当于八进制表示 `666`。
|
||||
|
||||
我们可以对目录执行相同的操作,并看到其默认权限为 `777`。我们需要在目录上使用“执行”位,以便可以遍历它们。
|
||||
|
||||
```
|
||||
$ mkdir dir-umask-000
|
||||
$ ls -ld dir-umask-000
|
||||
drwxrwxrwx. 2 root root 4096 Jul 17 22:03 dir-umask-000/
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
管理员还有许多其他方法可以控制对系统文件的访问。这些权限是 Linux 的基本权限,我们可以在这些基础上进行构建。如果你的工作将你带入 FACL 或 SELinux,你会发现它们也建立在这些文件访问的首要规则之上。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/linux-permissions-101
|
||||
|
||||
作者:[Alex Juarez][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mralexjuarezhttps://opensource.com/users/marcobravohttps://opensource.com/users/greg-p
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux-penguins.png?itok=yKOpaJM_ (Penguins)
|
||||
[2]: https://www.gnu.org/software/texinfo/manual/info-stnd/info-stnd.html
|
||||
[3]: https://www.theurbanpenguin.com/using-a-simple-c-program-to-explain-the-suid-permission/
|
@ -0,0 +1,272 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (jdh8383)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to program with Bash: Syntax and tools)
|
||||
[#]: via: (https://opensource.com/article/19/10/programming-bash-part-1)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
怎样用 Bash 编程:语法和工具
|
||||
======
|
||||
让我们通过本系列文章来学习基本的 Bash 编程语法和工具,以及如何使用变量和控制运算符,这是三篇中的第一篇。
|
||||
![bash logo on green background][1]
|
||||
|
||||
Shell 是操作系统的命令解释器,其中 Bash 是我最喜欢的。每当用户或者系统管理员将命令输入系统的时候,Linux 的 shell 解释器就会把这些命令转换成操作系统可以理解的形式。而执行结果返回 shell 程序后,它会将结果输出到 STDOUT(标准输出),默认情况下,这些结果会[显示在你的终端][2]。所有我熟悉的 shell 同时也是门编程语言。
|
||||
|
||||
Bash 是个功能强大的 shell,包含众多便捷特性,比如:tab 补全、命令回溯和再编辑、aliases 别名等。它的命令行默认编辑模式是 Emacs,但是我最喜欢的Bash特性之一是我可以将其更改为 Vi 模式,以使用那些储存在我肌肉记忆中的的编辑命令。
|
||||
|
||||
然而,如果你把 Bash 当作单纯的 shell 来用,则无法体验它的真实能力。我在设计一套包含三卷的 [Linux 自学课程][3]时(这个系列的文章正是基于此课程),了解到许多 Bash 的知识,这些是我在过去 20 年的 Linux 工作经验中所没有掌握的,其中的一些知识就是关于 Bash 的编程用法。不得不说,Bash 是一门强大的编程语言,是一个能够同时用于命令行和 shell 脚本的完美设计。
|
||||
|
||||
本系列文章将要探讨如何使用 Bash 作为命令行界面(CLI)编程语言。第一篇文章简单介绍 Bash 命令行编程、变量以及控制运算符。其他文章会讨论诸如:Bash 文件的类型;字符串、数字和一些逻辑运算符,它们能够提供代码执行流程中的逻辑控制;不同类型的 shell 扩展;通过 **for**、**while** 和 **until** 来控制循环操作。
|
||||
|
||||
### Shell
|
||||
|
||||
Shell 是操作系统的命令解释器,其中 Bash 是我最喜欢的。每当用户或者系统管理员将命令输入系统的时候,Linux 的 shell 解释器就会把这些命令转换成操作系统可以理解的形式。而执行结果返回 shell 程序后,它会将结果输出到终端。所有我熟悉的 shell 同时也是门编程语言。
|
||||
|
||||
Bash 是 Bourne Again Shell 的缩写,因为 Bash shell 是 [基于][4] 更早的 Bourne shell,后者是 Steven Bourne 在 1977 年开发的。另外还有很多[其他的 shell][5] 可以使用,但下面四个是我经常见到的:
|
||||
|
||||
* **csh:** C shell 适合那些习惯了 C 语言语法的开发者。
|
||||
* **ksh:** Korn shell,由 David Korn 开发,在 Unix 用户中更流行。
|
||||
* **tcsh:** 一个 csh 的变种,增加了一些易用性。
|
||||
* **zsh:** Z shell,集成了许多其他流行 shell 的特性。
|
||||
|
||||
|
||||
|
||||
所有 shell 都有内置命令,用以补充或替代核心工具集。打开 shell 的 man 说明页,找到“BUILT-INS”那一段,可以查看都有哪些内置命令。
|
||||
|
||||
|
||||
每种 shell 都有它自己的特性和语法风格。我用过 csh、ksh 和 zsh,但我还是更喜欢 Bash。你可以多试几个,寻找更适合你的 shell,尽管这可能需要花些功夫。但幸运的是,切换不同 shell 很简单。
|
||||
|
||||
所有这些 shell 既是编程语言又是命令解释器。下面我们来快速浏览一下 Bash 中集成的编程结构和工具。
|
||||
|
||||
### 做为编程语言的 Bash
|
||||
|
||||
大多数场景下,系统管理员都会使用 Bash 来发送简单明了的命令。但 Bash 不仅可以输入单条命令,很多系统管理员可以编写简单的命令行程序来执行一系列任务,这些程序可以作为通用工具,能节省时间和精力。
|
||||
|
||||
编写 CLI 程序的目的是要提高效率(做一个“懒惰的”系统管理员)。在 CLI 程序中,你可以用特定顺序列出若干命令,逐条执行。这样你就不用盯着显示屏,等待一条命令执行完,再输入另一条,省下来的时间就可以去做其他事情了。
|
||||
|
||||
### 什么是“程序”?
|
||||
|
||||
自由在线计算机词典([FOLDOC][6])对于程序的定义是:“由计算机执行的指令,而不是运行它们的物理硬件。”普林斯顿大学的 [WordNet][7] 将程序定义为:“……计算机可以理解并执行的一系列指令……”[维基百科][8]上也有一条不错的关于计算机程序的条目。
|
||||
|
||||
总结下,程序由一条或多条指令组成,目的是完成一个具体的相关任务。对于系统管理员而言,一段程序通常由一系列的 shell 命令构成。Linux 下所有的 shell (至少我所熟知的)都有基本的编程功能,Bash 作为大多数 linux 发行版的默认 shell,也不例外。
|
||||
|
||||
本系列用 Bash 举例(因为它无处不在),假如你使用一个不同的 shell 也没关系,尽管结构和语法有所不同,但编程思想是相通的。有些 shell 支持某种特性而其他 shell 则不支持,但它们都提供编程功能。Shell 程序可以被存在一个文件中被反复使用,或者在需要的时候才创建它们。
|
||||
|
||||
|
||||
### 简单 CLI 程序
|
||||
|
||||
最简单的命令行程序只有一或两条语句,它们可能相关,也可能无关,在按**回车**键之前被输入到命令行。程序中的第二条语句(如果有的话)可能取决于第一条语句的操作,但也不是必须的。
|
||||
|
||||
这里需要特别讲解一个标点符号。当你在命令行输入一条命令,按下**回车**键的时候,其实在命令的末尾有一个隐含的分号(**;**)。当一段 CLI shell 程序在命令行中被串起来作为单行指令使用时,必须使用分号来终结每个语句并将其与下一条语句分开。但 CLI shell 程序中的最后一条语句可以使用显式或隐式的分号。
|
||||
|
||||
### 一些基本语法
|
||||
|
||||
下面的例子会阐明这一语法规则。这段程序由单条命令组成,还有一个显式的终止符:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ echo "Hello world." ;
|
||||
Hello world.
|
||||
```
|
||||
|
||||
看起来不像一个程序,但它确是我学习每个新编程语言时写下的第一个程序。不同语言可能语法不同,但输出结果是一样的。
|
||||
|
||||
让我们扩展一下这段微不足道却又无所不在的代码。你的结果可能与我的有所不同,因为我的家目录有点乱,而你可能是在 GUI 桌面中第一次登陆账号。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ echo "My home directory." ; ls ;
|
||||
My home directory.
|
||||
chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6
|
||||
chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir
|
||||
TestFile1 Desktop dmesg.txt link3 Public testdir Videos
|
||||
TestFile1.dos dmesg1.txt Documents Music random.txt testdir1
|
||||
```
|
||||
|
||||
现在是不是更明显了。结果是相关的,但是两条语句彼此独立。你可能注意到我喜欢在分号前后多输入一个空格,这样会让代码的可读性更好。让我们再运行一遍这段程序,这次不要带结尾的分号:
|
||||
|
||||
|
||||
```
|
||||
`[student@studentvm1 ~]$ echo "My home directory." ; ls`
|
||||
```
|
||||
|
||||
输出结果没有区别。
|
||||
|
||||
### 关于变量
|
||||
|
||||
像所有其他编程语言一样,Bash 支持变量。变量是个象征性的名字,它指向内存中的某个位置,那里存着对应的值。变量的值是可以改变的,所以它叫“变~量”。
|
||||
|
||||
Bash 不像 C 之类的语言,需要强制指定变量类型,比如:整型、浮点型或字符型。在 Bash 中,所有变量都是字符串。整数型的变量可以被用于整数运算,这是 Bash 唯一能够处理的数学类型。更复杂的运算则需要借助 [**bc**][9] 这样的命令,可以被用在命令行编程或者脚本中。
|
||||
|
||||
变量的值是被预先分配好的,这些值可以用在命令行编程或者脚本中。可以通过变量名字给其赋值,但是不能使用 **$** 符开头。比如,**VAR=10** 这样会把 VAR 的值设为 10。要打印变量的值,你可以使用语句 **echo $VAR**。变量名必须以文本(即非数字)开始。
|
||||
|
||||
Bash 会保存已经定义好的变量,直到它们被取消掉。
|
||||
|
||||
下面这个例子,在变量被赋值前,它的值是空(null)。然后给它赋值并打印出来,检验一下。你可以在同一行 CLI 程序里完成它:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ;
|
||||
|
||||
Hello World
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
_注意:变量赋值的语法非常严格,等号(**=**)两边不能有空格。_
|
||||
|
||||
那个空行表明了 **MyVar** 的初始值为空。变量的赋值和改值方法都一样,这个例子展示了原始值和新的值。
|
||||
|
||||
正如之前说的,Bash 支持整数运算,当你想计算一个数组中的某个元素的位置,或者做些简单的算术运算,这还是挺有帮助的。然而,这种方法并不适合科学计算,或是某些需要小数运算的场景,比如财务统计。这些场景有其它更好的工具可以应对。
|
||||
|
||||
下面是个简单的算术题:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"
|
||||
Result = 63
|
||||
```
|
||||
|
||||
好像没啥问题,但如果运算结果是浮点数会发生什么呢?
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var1/Var2))"
|
||||
Result = 0
|
||||
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = $((Var2/Var1))"
|
||||
Result = 1
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
结果会被取整。请注意运算被包含在 **echo** 语句之中,其实计算在 echo 命令结束前就已经完成了,原因是 Bash 的内部优先级。想要了解详情的话,可以在 Bash 的 man 页面中搜索 "precedence"。
|
||||
|
||||
### 控制运算符
|
||||
|
||||
Shell 的控制运算符是一种语法运算符,可以轻松地创建一些有趣的命令行程序。在命令行上按顺序将几个命令串在一起,就变成了最简单的 CLI 程序:
|
||||
|
||||
|
||||
```
|
||||
`command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;`
|
||||
```
|
||||
|
||||
只要不出错,这些命令都能顺利执行。但假如出错了怎么办?你可以预设好应对出错的办法,这就要用到 Bash 内置的控制运算符, **&&** 和 **||**。这两种运算符提供了流程控制功能,使你能改变代码执行的顺序。分号也可以被看做是一种 Bash 运算符,预示着新一行的开始。
|
||||
|
||||
|
||||
**&&** 运算符提供了如下简单逻辑,“如果 command1 执行成功,那么接着执行 command2。如果 command1 失败,就跳过 command2。”语法如下:
|
||||
|
||||
|
||||
```
|
||||
`command1 && command2`
|
||||
```
|
||||
|
||||
现在,让我们用命令来创建一个新的目录,如果成功的话,就把它切换为当前目录。确保你的家目录(**~**)是当前目录,先尝试在 **/root** 目录下创建,你应该没有权限:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir/ &&; cd $Dir
|
||||
mkdir: cannot create directory '/root/testdir/': Permission denied
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
上面的报错信息是由 **mkdir** 命令抛出的,因为创建目录失败了。**&&** 运算符收到了非零的返回码,所以 **cd** 命令就被跳过,前者阻止后者继续运行,因为创建目录失败了。这种控制流程可以阻止后面的错误累积,避免引发更严重的问题。是时候讲点更复杂的逻辑了。
|
||||
|
||||
当一段程序的返回码大于零时,使用 **||** 运算符可以让你在后面接着执行另一段程序。简单语法如下:
|
||||
|
||||
|
||||
```
|
||||
`command1 || command2`
|
||||
```
|
||||
|
||||
解读一下,“假如 command1 失败,执行 command2”。隐藏的逻辑是,如果 command1 成功,跳过 command2。下面实践一下,仍然是创建新目录:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir || echo "$Dir was not created."
|
||||
mkdir: cannot create directory '/root/testdir': Permission denied
|
||||
/root/testdir was not created.
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
正如预期,因为目录无法创建,第一条命令失败了,于是第二条命令被执行。
|
||||
|
||||
把 **&&** 和 **||** 两种运算符结合起来才能发挥它们的最大功效。请看下面例子中的流程控制方法:
|
||||
|
||||
|
||||
```
|
||||
`preceding commands ; command1 && command2 || command3 ; following commands`
|
||||
```
|
||||
|
||||
语法解释:“假如 command1 退出时返回码为零,就执行 command2,否则执行 command3。”用具体代码试试:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
|
||||
mkdir: cannot create directory '/root/testdir': Permission denied
|
||||
/root/testdir was not created.
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
现在我们再试一次,用你的家目录替换 **/root** 目录,你将会有权限创建这个目录了:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 ~]$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
像 **command1 && command2** 这样的控制语句能够运行的原因是,每条命令执行完毕时都会给 shell 发送一个返回码,用来表示它执行成功与否。默认情况下,返回码为 0 表示成功,其他任何正值表示失败。一些系统管理员使用的工具用值为 1 的返回码来表示失败,但其他很多程序使用别的数字来表示失败。
|
||||
|
||||
Bash 的内置变量 **$?** 可以显示上一条命令的返回码,可以在脚本或者命令行中非常方便地检查它。要查看返回码,让我们从运行一条简单的命令开始,返回码的结果总是上一条命令给出的。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ll ; echo "RC = $?"
|
||||
total 1264
|
||||
drwxrwxr-x 2 student student 4096 Mar 2 08:21 chapter25
|
||||
drwxrwxr-x 2 student student 4096 Mar 21 15:27 chapter26
|
||||
-rwxr-xr-x 1 student student 92 Mar 20 15:53 TestFile1
|
||||
drwxrwxr-x. 2 student student 663552 Feb 21 14:12 testdir
|
||||
drwxr-xr-x. 2 student student 4096 Dec 22 13:15 Videos
|
||||
RC = 0
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
在这个例子中,返回码为零,意味着命令执行成功了。现在对 root 的家目录测试一下,你应该没有权限:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ll /root ; echo "RC = $?"
|
||||
ls: cannot open directory '/root': Permission denied
|
||||
RC = 2
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
本例中返回码是 2,表明非 root 用户没有权限进入这个目录。你可以利用这些返回码,用控制运算符来改变程序执行的顺序。
|
||||
|
||||
### 总结
|
||||
|
||||
本文将 Bash 看作一门编程语言,并从这个视角介绍了它的简单语法和基础工具。我们学习了如何将数据输出到 STDOUT,怎样使用变量和控制运算符。在本系列的下一篇文章中,将会重点介绍能够控制指令执行流程的逻辑运算符。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/programming-bash-part-1
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[jdh8383](https://github.com/jdh8383)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dboth
|
||||
[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://opensource.com/article/18/10/linux-data-streams
|
||||
[3]: http://www.both.org/?page_id=1183
|
||||
[4]: https://opensource.com/19/9/command-line-heroes-bash
|
||||
[5]: https://en.wikipedia.org/wiki/Comparison_of_command_shells
|
||||
[6]: http://foldoc.org/program
|
||||
[7]: https://wordnet.princeton.edu/
|
||||
[8]: https://en.wikipedia.org/wiki/Computer_program
|
||||
[9]: https://www.gnu.org/software/bc/manual/html_mono/bc.html
|
@ -0,0 +1,260 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wenwensnow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to dual boot Windows 10 and Debian 10)
|
||||
[#]: via: (https://www.linuxtechi.com/dual-boot-windows-10-debian-10/)
|
||||
[#]: author: (James Kiarie https://www.linuxtechi.com/author/james/)
|
||||
|
||||
如何拥有一个Windows 10 和 Debian 10 的双系统
|
||||
======
|
||||
|
||||
所以,在无数次劝说自己后,你终于做出了一个大胆的决定,试试**Linux**。 不过,在完全熟悉Linux之前,你依旧需要使用Windows 10系统。幸运的是,通过一个双系统引导设置,能让你在启动时,选择自己想要进入的系统。在这个指南中,你会看到如何 **如何双重引导Windows 10 和 Debian 10**.
|
||||
|
||||
[![如何拥有一个Windows 10 和 Debian 10 的双系统][1]][2]
|
||||
|
||||
### 前提条件
|
||||
|
||||
在开始之前,确保你满足下列条件:
|
||||
|
||||
* 一个Debian10 的可引导USB或DVD
|
||||
* 一个快速且稳定的网络 (为了安装更新 & 以及第三方软件)
|
||||
|
||||
另外,记得注意你系统的引导策略(UEFI 或Legacy), 需要确保两个系统使用同一种引导模式。
|
||||
|
||||
### 第一步:在硬盘上创建一个空余分区
|
||||
|
||||
第一步,你需要在你的硬盘上创建一个空余分区。之后,这将是我们安装Debian系统的地方。为了实现这一目的,需要使用下图所示的磁盘管理器:
|
||||
|
||||
同时按下 **Windows + R键**,启动运行程序。接下来,输入 **diskmgmt.msc** ,按 **回车键**
|
||||
|
||||
[![Launch-Run-dialogue][1]][3]
|
||||
|
||||
这会启动 **磁盘管理器**窗口,它会显示你Windows 上所有已有磁盘。
|
||||
|
||||
[![Disk-management][1]][4]
|
||||
|
||||
接下来,你需要为Debian安装创建空余空间。为此,你需要压缩其中一个磁盘的空间,从而创建一个未分配的新分区。在这个例子里,我会从 D 盘中创建一个 **30 GB** 的新分区。
|
||||
|
||||
为了压缩一个卷,右键点击它,然后选中选项 ‘**压缩**’
|
||||
|
||||
[![压缩卷][1]][5]
|
||||
|
||||
在弹出窗口中,定义你想压缩的空间大小。记住,这是将来要安装Debian 10的磁盘空间。我选择了 **30000MB ( 大约 30 GB)** 。 压缩完成后,点击‘**压缩**’.
|
||||
|
||||
[![Shrink-space][1]][6]
|
||||
|
||||
在压缩操作结束后,你会看到一个如下图所示的未分配分区:
|
||||
|
||||
[![未分配分区][1]][7]
|
||||
|
||||
完美! 现在可以准备开始安装了。
|
||||
|
||||
### 第二步:开始安装Debian 10
|
||||
|
||||
空余分区已经创建好了,将你的可引导USB或安装DVD插入电脑,重新启动系统。 记得更改 **BIOS** 中的**引导顺序**,需要在启动时按住功能键(通常,根据品牌不同,是**F9, F10 或 F12** 中的某一个)。 这一步骤,对系统是否能进入安装媒体来说,至关重要。保存 BIOS 设置,并重启电脑。
|
||||
|
||||
如下图所示,界面会显示一个新的引导菜单:点击 ‘**Graphical install**’
|
||||
[![图形化界面安装][1]][8]
|
||||
|
||||
下一步,选择你的 **偏好语言** ,然后点击 ‘**继续**’
|
||||
[![设置语言-Debian10][1]][9]
|
||||
|
||||
接着,选择你的 **地区** ,点击‘**继续**’。 根据地区,系统会自动选择当地对应的时区。 如果你无法找到你所对应的地区,将界面往下拉, 点击‘**其他**’后,选择相对应位置。
|
||||
|
||||
[![选择地区-Debain10][1]][10]
|
||||
|
||||
而后,选择你的 **keyboard** 布局。
|
||||
|
||||
[![设置键盘-Debain10][1]][11]
|
||||
|
||||
接下来,设置系统的 **主机名** ,点击 ‘**继续**’
|
||||
|
||||
[![Set-hostname-Debian10][1]][12]
|
||||
|
||||
下一步,确定 **域名**。如果你的电脑不在域中,直接点击 ‘**继续**’按钮。
|
||||
|
||||
[![设置域名-Debian10][1]][13]
|
||||
|
||||
然后,如图所示,设置 **root 密码**,点击 ‘**继续**’
|
||||
|
||||
[![设置root 密码-Debian10][1]][14]
|
||||
|
||||
下一步骤,设置账户的用户全名,点击 ‘**继续**’
|
||||
|
||||
[![设置用户全名-debain10][1]][15]
|
||||
|
||||
接着,通过设置 **username** 来确定此账户显示时的用户名
|
||||
|
||||
[![Specify-username-Debian10][1]][16]
|
||||
|
||||
下一步,设置用户密码, 点击‘**继续**’
|
||||
|
||||
[![设置用户密码-Debian10][1]][17]
|
||||
|
||||
然后,设置**时区**
|
||||
|
||||
[![设置时区-Debian10][1]][18]
|
||||
|
||||
这时,你要为Debian10安装创建分区。如果你是新手用户,点击菜单中的第一个选项, ‘**使用最大的连续空余空间**,点击‘**继续**’.
|
||||
|
||||
[![Use-largest-continuous-free-space-debian10][1]][19]
|
||||
|
||||
不过,如果你对创建分区有所了解的话,选择‘**手动**’ 选项,点击 ‘**继续**’
|
||||
|
||||
[![选择手动-Debain10][1]][20]
|
||||
|
||||
接着,选择被标记为 ‘**空余空间**’ 的磁盘, 点击‘**继续**’ 。接下来,点击‘**创建新分区**’
|
||||
|
||||
[![创建新分区-Debain10][1]][21]
|
||||
|
||||
|
||||
下一界面,首先确定swap空间大小。我的swap大小为**2GB**,点击 **继续**。
|
||||
|
||||
[![确定swap大小-debian10][1]][22]
|
||||
|
||||
点击下一界面的 ‘’**Primary**’ , 点击‘**继续**’
|
||||
|
||||
[![磁盘主分区-Debian10][1]][23]
|
||||
|
||||
选择在磁盘**初始位置创建新分区**后,点击继续.
|
||||
|
||||
[![在初始位置创建-Debain10][1]][24]
|
||||
|
||||
选择**Ext 4 日志文件系统** ,点击 ‘**继续**’
|
||||
|
||||
[![选择Ext4日志文件系统-debain10][1]][25]
|
||||
|
||||
下个界面选择 **swap** ,点击继续
|
||||
|
||||
[![选择swap-debian10][1]][26]
|
||||
|
||||
选中 **完成此分区设置** ,点击继续。
|
||||
|
||||
[!完成此分区设置-debian10][1]][27]
|
||||
|
||||
返回 **磁盘分区** 界面, 点击**空余空间** ,点击继续
|
||||
|
||||
[![点击空余空间-Debain10][1]][28]
|
||||
|
||||
为了让自己能轻松一点,选中**自动为空余空间分区** 后,点击 **继续**.
|
||||
|
||||
[![自动为空余空间分区-Debain10][1]][29]
|
||||
|
||||
接着点击 **将所有文件存储在同一分区 (新手用户推荐)**
|
||||
|
||||
[![将所有文件存储在同一分区-debian10][1]][30]
|
||||
|
||||
最后, 点击**完成分区设置,并将改动写入磁盘** ,点击 **继续**.
|
||||
|
||||
[![完成分区设置,并将改动写入磁盘][1]][31]
|
||||
|
||||
确定你要将改动写入磁盘,点击‘**Yes**’
|
||||
|
||||
[![将改动写入磁盘-Debian10][1]][32]
|
||||
|
||||
而后,安装程序会开始安装所有必要的软件包。
|
||||
|
||||
当系统询问是否要扫描其他CD时,选择 **No** ,并点击继续
|
||||
|
||||
[![扫描其他CD-No-Debain10][1]][33]
|
||||
|
||||
接着,选择离你最近的镜像站点地区,点击 ‘继续’
|
||||
|
||||
[![Debian-镜像站点-国家][1]][34]
|
||||
|
||||
然后,选择最适合你的镜像站点,点击‘**继续**’
|
||||
|
||||
[![选择镜像站点][1]][35]
|
||||
|
||||
如果你打算使用代理服务器,在下面输入具体信息,没有的话就留空,点击‘继续’
|
||||
|
||||
[![输入代理信息-debian10][1]][36]
|
||||
|
||||
随着安装进程的继续, 你会被问到,是否想参加一个**软件包用途调查**。 你可以选择任意一个选项,之后点击‘继续’ .我选择了‘**否**’。
|
||||
|
||||
[![参与调查-debain10][1]][37]
|
||||
|
||||
在 **软件选择** 窗口选中你想安装的软件包,点击**继续**.
|
||||
|
||||
[![软件选择-debian10][1]][38]
|
||||
|
||||
安装程序会将选中的软件一一安装,在这期间,你可以去喝杯咖啡休息一下。
|
||||
|
||||
系统将会询问你,是否要将 grub 的**引导装载程序** 安装到 **主引导记录表 (MBR)** 上。点击 **Yes**,而后点击 **继续**.
|
||||
|
||||
[![安装-grub-bootloader-debian10][1]][39]
|
||||
|
||||
接着,选中你想安装**grub** 的硬盘,点击**继续**
|
||||
|
||||
[![选择硬盘-安装grub-Debian10][1]][40]
|
||||
|
||||
最后, 安装完成,直接点击 ‘**继续**’ 按钮
|
||||
|
||||
[![安装完成-重新启动-debian10][1]][41]
|
||||
|
||||
你现在应该会有一个列出**Windows** 和**Debian** 的grub 菜单。 为了引导Debian系统,往下选择Debian。之后,你就能看见登录界面。输入密码之后,点击回车键。
|
||||
|
||||
[![Debian10-登录][1]][42]
|
||||
|
||||
这就完成了!这样,你就拥有了一个全新的Debian 10 和Windows 10双系统。
|
||||
|
||||
[![Debian10-Buster-Details][1]][43]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxtechi.com/dual-boot-windows-10-debian-10/
|
||||
|
||||
作者:[James Kiarie][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.linuxtechi.com/author/james/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]: https://www.linuxtechi.com/wp-content/uploads/2019/10/How-to-dual-boot-Windows-and-Debian10.jpg
|
||||
[3]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Launch-Run-dialogue.jpg
|
||||
[4]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Disk-management.jpg
|
||||
[5]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Shrink-volume.jpg
|
||||
[6]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Shrink-space.jpg
|
||||
[7]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Unallocated-partition.jpg
|
||||
[8]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Graphical-Install-Debian10.jpg
|
||||
[9]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Language-Debian10.jpg
|
||||
[10]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-location-Debain10.jpg
|
||||
[11]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Configure-Keyboard-layout-Debain10.jpg
|
||||
[12]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Set-hostname-Debian10.jpg
|
||||
[13]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Set-domain-name-Debian10.jpg
|
||||
[14]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Set-root-Password-Debian10.jpg
|
||||
[15]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Specify-fullname-user-debain10.jpg
|
||||
[16]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Specify-username-Debian10.jpg
|
||||
[17]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Specify-user-password-Debian10.jpg
|
||||
[18]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Configure-timezone-Debian10.jpg
|
||||
[19]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Use-largest-continuous-free-space-debian10.jpg
|
||||
[20]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Manual-Debain10.jpg
|
||||
[21]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Create-new-partition-Debain10.jpg
|
||||
[22]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Define-swap-space-debian10.jpg
|
||||
[23]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Partition-Disks-Primary-Debain10.jpg
|
||||
[24]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Start-at-the-beginning-Debain10.jpg
|
||||
[25]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Ext4-Journaling-system-debain10.jpg
|
||||
[26]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-swap-debain10.jpg
|
||||
[27]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Done-setting-partition-debian10.jpg
|
||||
[28]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Click-Free-space-Debain10.jpg
|
||||
[29]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Automatically-partition-free-space-Debain10.jpg
|
||||
[30]: https://www.linuxtechi.com/wp-content/uploads/2019/10/All-files-in-one-partition-debian10.jpg
|
||||
[31]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Finish-partitioning-write-changes-to-disk.jpg
|
||||
[32]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Write-changes-to-disk-Yes-Debian10.jpg
|
||||
[33]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Scan-another-CD-No-Debain10.jpg
|
||||
[34]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Debian-archive-mirror-country.jpg
|
||||
[35]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-Debian-archive-mirror.jpg
|
||||
[36]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Enter-proxy-details-debian10.jpg
|
||||
[37]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Participate-in-survey-debain10.jpg
|
||||
[38]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Software-selection-debian10.jpg
|
||||
[39]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Install-grub-bootloader-debian10.jpg
|
||||
[40]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Select-hard-drive-install-grub-Debian10.jpg
|
||||
[41]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Installation-complete-reboot-debian10.jpg
|
||||
[42]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Debian10-log-in.jpg
|
||||
[43]: https://www.linuxtechi.com/wp-content/uploads/2019/10/Debian10-Buster-Details.jpg
|
@ -0,0 +1,110 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Keyboard Shortcuts to Speed Up Your Work in Linux)
|
||||
[#]: via: (https://opensourceforu.com/2019/11/keyboard-shortcuts-to-speed-up-your-work-in-linux/)
|
||||
[#]: author: (S Sathyanarayanan https://opensourceforu.com/author/s-sathyanarayanan/)
|
||||
|
||||
在 Linux 中加速工作的键盘快捷键
|
||||
======
|
||||
|
||||
[![Google Keyboard][1]][2]
|
||||
|
||||
_操作鼠标、键盘和菜单会占用我们很多时间,这些可以使用键盘快捷键来节省时间。这不仅节省时间,还可以使用户更高效。_
|
||||
|
||||
你是否意识到每次在打字时从键盘切换到鼠标最多需要两秒钟?如果一个人每天工作八小时,每分钟从键盘切换到鼠标一次,并且一年中大约有 240 个工作日,那么所浪费的时间(根据 Brainscape 的计算)为:
|
||||
_ [每分钟浪费 2 秒] x [每天 480 分钟] x每年 240 个工作日=每年浪费 64 小时_
|
||||
这相当于损失了八个工作日,因此学习键盘快捷键将使生产率提高 3.3%(_<https://www.brainscape.com/blog/2011/08/keyboard-shortcuts-economy/>_)。
|
||||
|
||||
键盘快捷键提供了一种更快的方式来执行任务,不然就需要使用鼠标和/或菜单分多个步骤来完成。图 1 列出了 Ubuntu 18.04 Linux 和 Web 浏览器中一些最常用的快捷方式。我省略了非常有名的快捷方式,例如复制、粘贴等,以及不经常使用的快捷方式。读者可以参考在线资源以获得完整的快捷方式列表。请注意,Windows 键在 Linux 中被重命名为 Super 键。
|
||||
|
||||
**常规快捷方式**
|
||||
下面列出了常规快捷方式。
|
||||
|
||||
[![][3]][4]
|
||||
**打印屏幕和屏幕录像**
|
||||
以下快捷方式可用于打印屏幕或录制屏幕视频。
|
||||
[![][5]][6]
|
||||
**在应用之间切换**
|
||||
此处列出的快捷键可用于在应用之间切换。
|
||||
|
||||
[![][7]][8]
|
||||
**平铺窗口**
|
||||
可以使用下面提供的快捷方式以不同方式将窗口平铺。
|
||||
|
||||
[![][9]][10]
|
||||
|
||||
**浏览器快捷方式**
|
||||
此处列出了浏览器最常用的快捷方式。大多数快捷键对于 Chrome/Firefox 浏览器是通用的。
|
||||
|
||||
**组合键** | **行为**
|
||||
---|---
|
||||
|
||||
Ctrl + T | 打开一个新标签。
|
||||
Ctrl + Shift + T | 打开最近关闭的标签。
|
||||
Ctrl + D | 添加一个新书签。
|
||||
Ctrl + W | 关闭浏览器标签。
|
||||
Alt + D | 将光标置于浏览器的地址栏中。
|
||||
F5 或 Ctrl-R | 刷新页面。
|
||||
Ctrl + Shift + Del | 清除私人数据和历史记录。
|
||||
Ctrl + N | 打开一个新窗口。
|
||||
Home| 滚动到页面顶部。
|
||||
End | 滚动到页面底部。
|
||||
Ctrl + J | 打开下载文件夹(在Chrome中)
|
||||
F11 | 全屏视图(切换效果)
|
||||
|
||||
**终端快捷方式**
|
||||
这是终端快捷方式的列表。
|
||||
[![][11]][12]
|
||||
你还可以在 Ubuntu 中配置自己的自定义快捷方式,如下所示:
|
||||
|
||||
|
||||
* 在 Ubuntu Dash 中单击设置。
|
||||
* 在“设置”窗口的左侧菜单中选择“设备”选项卡。
|
||||
* 在设备菜单中选择键盘标签。
|
||||
* 右面板的底部有个 “+” 按钮。点击 “+” 号打开自定义快捷方式对话框并配置新的快捷方式。
|
||||
|
||||
|
||||
|
||||
学习本文提到的三个快捷方式可以节省大量时间,并使你的工作效率更高。
|
||||
|
||||
**引用**
|
||||
_Cohen, Andrew. How keyboard shortcuts could revive America’s economy; [www.brainscape.com][13]. [Online] Brainscape, 26 May 2017; <https://www.brainscape.com/blog/2011/08/keyboard-shortcuts-economy/>_
|
||||
|
||||
![Avatar][14]
|
||||
|
||||
[S Sathyanarayanan][15]
|
||||
|
||||
作者目前在斯里萨蒂亚赛古尔巴加人类卓越大学工作。他在系统管理和 IT 课程教学方面拥有 25 年以上的经验。他是 FOSS 的积极推动者,可以通过 [sathyanarayanan.brn@gmail.com][16] 与他联系。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensourceforu.com/2019/11/keyboard-shortcuts-to-speed-up-your-work-in-linux/
|
||||
|
||||
作者:[S Sathyanarayanan][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensourceforu.com/author/s-sathyanarayanan/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2016/12/Google-Keyboard.jpg?resize=696%2C418&ssl=1 (Google Keyboard)
|
||||
[2]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2016/12/Google-Keyboard.jpg?fit=750%2C450&ssl=1
|
||||
[3]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/1.png?resize=350%2C319&ssl=1
|
||||
[4]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/1.png?ssl=1
|
||||
[5]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/NW.png?resize=350%2C326&ssl=1
|
||||
[6]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/NW.png?ssl=1
|
||||
[7]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/2.png?resize=350%2C264&ssl=1
|
||||
[8]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/2.png?ssl=1
|
||||
[9]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/3.png?resize=350%2C186&ssl=1
|
||||
[10]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/3.png?ssl=1
|
||||
[11]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/7.png?resize=350%2C250&ssl=1
|
||||
[12]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/7.png?ssl=1
|
||||
[13]: http://www.brainscape.com
|
||||
[14]: https://secure.gravatar.com/avatar/736684a2707f2ed7ae72675edf7bb3ee?s=100&r=g
|
||||
[15]: https://opensourceforu.com/author/s-sathyanarayanan/
|
||||
[16]: mailto:sathyanarayanan.brn@gmail.com
|
Loading…
Reference in New Issue
Block a user