mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-25 23:11:02 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
32761581f9
@ -0,0 +1,251 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (My journey to becoming an open source maintainer)
|
||||
[#]: via: (https://opensource.com/article/19/11/journey-open-source-maintainer)
|
||||
[#]: author: (Juliano Alves https://opensource.com/users/juliano)
|
||||
|
||||
My journey to becoming an open source maintainer
|
||||
======
|
||||
Hacktoberfest got me thinking. My first contribution to open source was
|
||||
challenging, but everything I've learned since then has made me a better
|
||||
developer.
|
||||
![Guy on a laptop on a building][1]
|
||||
|
||||
[Hacktoberfest][2] is an initiative that invites developers from around the world to participate and contribute to open source. This is the second year in a row that I participated to completion of the challenge, and I was so inspired by it that I want to share my slightly longer journey to open source software.
|
||||
|
||||
### A long time ago, in a galaxy far, far away…
|
||||
|
||||
The year was 2010. The universe made its move to make me cross paths with my good friend, [Jonas Abreu][3]. Jonas is the creator of [Mirror][4], a simple domain-specific language (DSL) layer over the Java Reflection API, which makes [meta-programming][5] easier. There was a feature request open for a proxy creation capability, and Jonas asked me if I was interested in implementing it. I accepted the challenge.
|
||||
|
||||
I suffered for three days, dealing with code that I didn’t understand… until I did. I still remember the feeling that my triumph brought me that day. That pain was knowledge invading my brain!
|
||||
|
||||
This code was my first contribution to open source. I took quite a lot away from my experience contributing to Mirror:
|
||||
|
||||
* A lot about Java meta-programming
|
||||
* The concept of proxy classes
|
||||
* [Javassist][6] and [cglib][7] frameworks
|
||||
* How to receive and provide useful and respectful feedback
|
||||
* How to design a tool that will be used by others
|
||||
* Some interesting [dark magic][8]
|
||||
|
||||
|
||||
|
||||
Most importantly, I took away a sense of purpose. I love the idea of contributing to the greater good while challenging myself and working with brilliant engineers who were way smarter than me.
|
||||
|
||||
### Exploring ways to contribute to open source
|
||||
|
||||
I started taking part in community initiatives, like running coding dojos. While doing this, I met more great devs, and we started a small group. At some point, that group decided to learn Scala. We studied and coded together, and eventually started [Scaladores][9], the Scala user group of São Paulo.
|
||||
|
||||
Eventually, Jonas started talking about a different approach for learning, called [deliberate practice][10].
|
||||
|
||||
> _What if we could put all this recently acquired knowledge altogether?_
|
||||
|
||||
The resulting project from studying this practice is [Aprenda][11], a learning platform that mixes gamification and deliberate practice to make it easier to learn HTML, regular expressions, or Git. Building something this significant felt like leveling up in my pursuit of open source contribution. I also found that I picked up more knowledge about programming and practices to motivate both others and myself.
|
||||
|
||||
As much as I enjoyed this pursuit, I couldn’t dedicate a lot of time to this project. At the same time as I was making progress on Aprenda, I had to shift focus to a new job.
|
||||
|
||||
### Contributing through my own Ruby gem
|
||||
|
||||
My new work had me in a common pattern: Every problem was solved by writing code that creates, reads, updates, or deletes data (CRUD). It gave me an idea, so I started a new project. I wanted to generate code the same way Ruby on Rails, a powerful web framework, allowed me to set up an environment with a simple command: **rails g scaffold**. Using [Thor][12], the same gem that powers Rails generators, I created [Spring MVC Scaffold][13]. Now, any time I needed to create a CRUD I typed:
|
||||
|
||||
|
||||
```
|
||||
$ springmvc scaffold product name:string value:double active:boolean
|
||||
```
|
||||
|
||||
The code I wrote reducing the work my team had to do to get their job done, and I shared it further by posting it publicly. Here are some of the highlights of what I learned:
|
||||
|
||||
* Generating code and files with Thor
|
||||
* Defining commands for a CLI
|
||||
* Organizing Ruby lib code
|
||||
* Creating a Ruby gem
|
||||
* Building projects with [Travis CI][14]
|
||||
* Publishing to RubyGems
|
||||
|
||||
|
||||
|
||||
> _After solving a common problem, think about making that solution available. Most likely, other people have similar problems._
|
||||
|
||||
Even though it’s not being maintained anymore, Spring MVC Scaffold is still available on [RubyGems][15]. And I tell you what, after that project, I went to work in a tech environment full of problems.
|
||||
|
||||
### Shifting technology
|
||||
|
||||
My new work required a shift in languages. I started working with Microsoft .NET, and I found issues that other communities had already solved. That recognition excited me because I knew it was my opportunity. My new opportunity to contribute came in the form of porting those solutions.
|
||||
|
||||
#### Selenia
|
||||
|
||||
[Selenium][16] is the dominate way to programmatically interact with websites as if the code is a "real" user (accessing it via a web browser). The API has always been too complex in my opinion. So I built a tool, we called Selenia, that could be used to write concise UI tests in C#, so instead of using:
|
||||
|
||||
|
||||
```
|
||||
IWebDriver driver;
|
||||
ChromeOptions options = [new][17] ChromeOptions();
|
||||
options.addExtensions([new][17] File("/path/to/extension.crx"));
|
||||
ChromeDriver driver = [new][17] ChromeDriver(options);
|
||||
driver = [new][17] ChromeDriver();
|
||||
driver.Navigate().GoToUrl("<http://www.google.com/ncr>");
|
||||
|
||||
IWebElement query = driver.FindElement(By.Name("q"));
|
||||
query.SendKeys("Selenium");
|
||||
query.Submit();
|
||||
|
||||
driver.Quit();
|
||||
```
|
||||
|
||||
We can write as:
|
||||
|
||||
|
||||
```
|
||||
Open("<http://www.google.com/>");
|
||||
S(By.Name("q").Value("Selenia").Enter();
|
||||
```
|
||||
|
||||
Selenium users may have a question at this point. If you are wondering, the answer is "no." It’s not necessary to close the driver yourself.
|
||||
|
||||
#### Designing for immutability with Ioget
|
||||
|
||||
Immutability, which means never changing an object that already exists, makes a developer’s life easy. This opinion is a newer one, however. Back in the day, ASP.NET MVCs would recommend updating information in place. The only way to instantiate objects was via **setters**.
|
||||
|
||||
I built [Ioget][18] to help with unmarshalling request parameters in web applications. HTTP request parameters are strings, so Ioget looks for the best way to parse those params according to the given class, instantiating objects via their constructors and therefore making them immutable.
|
||||
|
||||
I published this project publicly to NuGet, but I never managed to integrate Ioget with ASP.NET like I intended to. I stopped working with Microsoft technology, and thus this project fell behind from its once lofty goals.
|
||||
|
||||
Continuing with my deliberate practice, I kept track of the lessons learned along the way.
|
||||
|
||||
* [Reification][19]
|
||||
* ASP.NET MVC internals
|
||||
* Monad implementation
|
||||
* .NET framework internals
|
||||
|
||||
|
||||
|
||||
I also took note of a pattern I used with Selenia. I really like this snippet, which I used to close the driver:
|
||||
|
||||
|
||||
```
|
||||
private void MarkForAutoClose(IWebDriver driver) =>
|
||||
AppDomain.CurrentDomain.DomainUnload += (s, e) => driver.Quit();
|
||||
```
|
||||
|
||||
### Contributing to Quill
|
||||
|
||||
I moved to London in 2016, which paused my contributions for a while. Eventually, I watched a talk by [Gustavo Amigo][20] about his project, [quill-pgsql][21], which is an extension to support PostgreSQL data types with [Quill][22]. He mentioned that this project was in its early moments, which meant it was ideal for someone to join, and I was interested in writing in Scala. After a few pull requests, I decided to contribute to the main project.
|
||||
|
||||
Quill transforms regular collection-like code into SQL queries in compile-time. I consider it the most challenging (and interesting) project I have ever contributed to. It’s been a few years since I started, and today I am [one of the maintainers][23].
|
||||
|
||||
Here’s what I learned by working on Quill:
|
||||
|
||||
* Abstract syntax trees (AST)
|
||||
* The Dark Arts (also known as [Scala macros][24])
|
||||
* How to make code extensible via [implicits][25]
|
||||
* Exclusive and weird [SQL rules][26]
|
||||
|
||||
|
||||
|
||||
Quill has a module called quill-async, which uses [an asynchronous database driver][27] that is no longer maintained. Quill’s creator, [Flavio Brasil][28], suggested that we could write a new async driver. That’s how [Non-Blocking Database Connectivity (NDBC)][29] got started.
|
||||
|
||||
NDBC is a fully async alternative to Java Database Connectivity (JDBC). Its architecture was designed to provide high-performance, non-blocking connectivity to the database on top of [Trane.io Futures][30] and [Netty 4][31]:
|
||||
|
||||
|
||||
```
|
||||
// Create a Config with an Embedded Postgres
|
||||
Config config = Config.create("io.trane.ndbc.postgres.netty4.DataSourceSupplier", "localhost", 0, "user")
|
||||
.database("test_schema")
|
||||
.password("test")
|
||||
.embedded("io.trane.ndbc.postgres.embedded.EmbeddedSupplier");
|
||||
|
||||
// Create a DataSource
|
||||
DataSource<[PreparedStatement][32], Row> ds = DataSource.fromConfig(config);
|
||||
|
||||
// Define a timeout
|
||||
Duration timeout = Duration.ofSeconds(10);
|
||||
|
||||
// Send a query to the db defining a timeout and receiving back a List
|
||||
List<Row> rows = ds.query("SELECT 1 AS value").get(timeout);
|
||||
|
||||
// iterate over awesome strongly typed rows
|
||||
rows.forEach(row -> [System][33].out.println(row.getLong("value")));
|
||||
```
|
||||
|
||||
More knowledge was acquired along the way:
|
||||
|
||||
* Understanding binary protocols
|
||||
* Using Netty 4
|
||||
* Weaknesses of the Java type system
|
||||
* Fully implementing functional structures
|
||||
|
||||
|
||||
|
||||
That’s where I am at the moment. I divide my attention between Quill and NDBC, trying to make them work together.
|
||||
|
||||
### Plans for the future
|
||||
|
||||
The contributions I have in mind for the near future are implementing:
|
||||
|
||||
* Array support in [Finagle Postgres][34]
|
||||
* A Clojure wrapper for NDBC
|
||||
* A ndbc-spring module
|
||||
* A CLI in [Rust][35]
|
||||
|
||||
|
||||
|
||||
I now have almost 10 years of open source in my journey, and it taught me something extremely valuable: Open source is about sharing knowledge. When I am solving an issue, I am acquiring knowledge. When I send a pull request, I am spreading that knowledge. Knowledge brings more knowledge!
|
||||
|
||||
I strongly recommend that you become part of the open source community. It can be difficult, especially in the beginning, but everything you will learn will make you a better developer. I promise.
|
||||
|
||||
> _Open source is about sharing knowledge. When I am solving an issue, I am acquiring knowledge. When I send a pull request, I am spreading that knowledge. Knowledge brings more knowledge!_
|
||||
|
||||
_This article was originally posted on [Juliano Alves' Programming Blog][36]. It has been edited for style and clarity._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/journey-open-source-maintainer
|
||||
|
||||
作者:[Juliano Alves][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/juliano
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_code_programming_laptop.jpg?itok=ormv35tV (Guy on a laptop on a building)
|
||||
[2]: https://hacktoberfest.digitalocean.com/
|
||||
[3]: https://twitter.com/jonasabreu
|
||||
[4]: http://projetos.vidageek.net/mirror/mirror/
|
||||
[5]: https://www.ibm.com/developerworks/library/l-metaprog1/index.html
|
||||
[6]: https://www.javassist.org/
|
||||
[7]: https://github.com/cglib/cglib
|
||||
[8]: https://github.com/vidageek/mirror/blob/master/src/main/java/net/vidageek/mirror/provider/java/ObjenesisConstructorBypassingReflectionProvider.java
|
||||
[9]: https://www.meetup.com/scaladores/
|
||||
[10]: https://jamesclear.com/deliberate-practice-theory
|
||||
[11]: https://aprenda.vidageek.net/
|
||||
[12]: http://whatisthor.com/
|
||||
[13]: https://github.com/juliano/springmvc-scaffold
|
||||
[14]: https://travis-ci.com/
|
||||
[15]: https://rubygems.org/gems/springmvc-scaffold
|
||||
[16]: https://www.seleniumhq.org/
|
||||
[17]: http://www.google.com/search?q=new+msdn.microsoft.com
|
||||
[18]: https://www.nuget.org/packages/Ioget/
|
||||
[19]: https://en.wikipedia.org/wiki/Reification_(computer_science)
|
||||
[20]: https://github.com/gustavoamigo
|
||||
[21]: https://github.com/gustavoamigo/quill-pgsql
|
||||
[22]: https://getquill.io/
|
||||
[23]: https://github.com/getquill/quill
|
||||
[24]: http://scalamacros.org/
|
||||
[25]: https://docs.scala-lang.org/tour/implicit-parameters.html
|
||||
[26]: https://teamsql.io/blog/?p=923
|
||||
[27]: https://github.com/mauricio/postgresql-async
|
||||
[28]: https://twitter.com/flaviowbrasil
|
||||
[29]: https://ndbc.io/
|
||||
[30]: http://trane.io/
|
||||
[31]: https://netty.io/
|
||||
[32]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+preparedstatement
|
||||
[33]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+system
|
||||
[34]: https://github.com/finagle/finagle-postgres/issues/55
|
||||
[35]: https://opensource.com/tags/rust
|
||||
[36]: https://juliano-alves.com/2019/11/02/the-journey-of-an-open-source-developer/
|
@ -0,0 +1,84 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Google to Add Mainline Linux Kernel Support to Android)
|
||||
[#]: via: (https://itsfoss.com/mainline-linux-kernel-android/)
|
||||
[#]: author: (John Paul https://itsfoss.com/author/john/)
|
||||
|
||||
Google to Add Mainline Linux Kernel Support to Android
|
||||
======
|
||||
|
||||
The current Android ecosystem is polluted with hundreds of different versions of Android, each running a different variant of the Linux kernel. Each version is designed for a different phone and it’s different configurations. Google has been working to fix the problem by adding the mainline Linux kernel to Android.
|
||||
|
||||
### How the Linux kernel is currently handled in Android
|
||||
|
||||
Before it reaches you, the Linux kernel on your cellphone goes through [three major steps][1].
|
||||
|
||||
First, Google takes the LTS (Long Term Support) version of the Linux kernel and adds all of the Android-specific code. This becomes the “Android Common kernel”.
|
||||
|
||||
Google then sends this code to the company that creates the System on a Chip (SoC) that runs your phone. This is usually Qualcomm.
|
||||
|
||||
Once the SoC maker finishes add code to support the CPU and other chips, the kernel is then passed on to the actual device maker, such as Samsung or Motorola. The device maker then adds code to support the rest of the phone, such as the display and camera.
|
||||
|
||||
Each of these steps takes a while to complete and results in a kernel that won’t work with any other device. It also means that the kernel is very old, usually about two years old. For example, the Google Pixel 4, which shipped last month, has a kernel from November 2017, which will never get updated.
|
||||
|
||||
Google has pledged to create security patches for older devices, which means they’re stuck keeping an eye on a huge hodge-podge of old code.
|
||||
|
||||
### The Future
|
||||
|
||||
![][2]
|
||||
|
||||
Last year, Google announced [plans][3] to fix this mess. This year they revealed what progress they made at the 2019 Linux Plumbers Conference.
|
||||
|
||||
> “We know what it takes to run Android but not necessarily on any given hardware. So our goal is to basically find all of that out, then upstream it and try to be as close to mainline as possible.”
|
||||
>
|
||||
> Sandeep Patil, [Android Kernel Team Lead][1]
|
||||
|
||||
They did show off a Xiaomi Poco F1 running Android with a proper Linux kernel. However, it some things did not [appear to be working][4], such as the battery percentage which was stuck at 0%.
|
||||
|
||||
So, how does Google plan to make this work? By taking a page from their [Project Treble][5] playbook. Before Project Treble, the low-level code that interacted with the device and Android itself was one big mess of code. Project Treble separated the two and made them modular so that Android updates could be shipped quicker and the low-level code could remain unchanged between updates.
|
||||
|
||||
Google wants to bring the same modularity to the kernel. Their [plan][1] “involves stabilizing Linux’s in-kernel ABI and having a stable interface for the Linux kernel and hardware vendors to write to. Google wants to decouple the Linux kernel from its hardware support.”
|
||||
|
||||
So this means that Google would ship a kernel and hardware drivers would be loaded as kernel modules. Currently, this is just a proposal. There are still quite a few technical problems that have to be solved. so, this won’t happen any time soon.
|
||||
|
||||
### Opposition from Open Source
|
||||
|
||||
The Open Source community will not be happy with the idea of putting proprietary code in the kernel. The [Linux kernel guidelines][6] state that drivers have to have a GPL license to be included in the kernel. They also point out that if a change in the driver causes an error, it will be resolved by the person who created the error. This means less work for device makers in the long run.
|
||||
|
||||
### Final Thoughts on including mainline kernel to Andorid
|
||||
|
||||
So far, this is just a proposal. There is a good chance that Google will start working on the project only to abandon it once they realize how much work this will take. Just take a look at how many projects Google has [already abandoned][7].
|
||||
|
||||
[Android Police][4] made a good point by mentioned that Google is working on its [Fuchsia operating system][8], which seems to have the goal of replacing Android one day.
|
||||
|
||||
So, the question is which monumental task will Google try to complete, getting Android running with a mainline Linux kernel or complete work on their unified Android replacement? Only time can answer that.
|
||||
|
||||
What are your thoughts on this topic? Please let us know in the comments below.
|
||||
|
||||
If you found this article interesting, please take a minute to share it on social media, Hacker News or [Reddit][9].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/mainline-linux-kernel-android/
|
||||
|
||||
作者:[John Paul][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://itsfoss.com/author/john/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://arstechnica.com/gadgets/2019/11/google-outlines-plans-for-mainline-linux-kernel-support-in-android/
|
||||
[2]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/mainline_linux_kernel_android.png?ssl=1
|
||||
[3]: https://lwn.net/Articles/771974/
|
||||
[4]: https://www.androidpolice.com/2019/11/19/google-wants-android-to-use-regular-linux-kernel-potentially-improving-updates-and-security/
|
||||
[5]: https://www.computerworld.com/article/3306443/what-is-project-treble-android-upgrade-fix-explained.html
|
||||
[6]: https://www.kernel.org/doc/Documentation/process/stable-api-nonsense.rst
|
||||
[7]: https://killedbygoogle.com/
|
||||
[8]: https://itsfoss.com/fuchsia-os-what-you-need-to-know/
|
||||
[9]: https://reddit.com/r/linuxusersgroup
|
@ -0,0 +1,209 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Install Ansible (Automation Tool) on CentOS 8/RHEL 8)
|
||||
[#]: via: (https://www.linuxtechi.com/install-ansible-centos-8-rhel-8/)
|
||||
[#]: author: (Pradeep Kumar https://www.linuxtechi.com/author/pradeep/)
|
||||
|
||||
How to Install Ansible (Automation Tool) on CentOS 8/RHEL 8
|
||||
======
|
||||
|
||||
**Ansible** is an awesome automation tool for Linux sysadmins. It is an open source configuration tool which allows sysadmins to manage hundreds of servers from one centralize node i.e **Ansible Server**. Ansible is the preferred configuration tool when it is compared with similar tools like **Puppet**, **Chef** and **Salt** because it doesn’t need any agent and it works on SSH and python.
|
||||
|
||||
[![Install-Ansible-CentOS8-RHEL8][1]][2]
|
||||
|
||||
In this tutorial we will learn how to install and use Ansible on CentOS 8 and RHEL 8 system
|
||||
|
||||
Ansible Lab Details:
|
||||
|
||||
* Minimal CentOS 8 / RHEL 8 Server (192.168.1.10) with Internet Connectivity
|
||||
* Two Ansible Nodes – Ubuntu 18.04 LTS (192.168.1.20) & CentOS 7 (192.168.1.30)
|
||||
|
||||
|
||||
|
||||
### Ansible Installation steps on CentOS 8
|
||||
|
||||
Ansible package is not available in default CentOS 8 package repository. so we need to enable [EPEL Repository][3] by executing the following command,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm -y
|
||||
```
|
||||
|
||||
Once the epel repository is enabled, execute the following dnf command to install Ansible
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo dnf install ansible
|
||||
```
|
||||
|
||||
Output of above command :
|
||||
|
||||
![dnf-install-ansible-centos8][1]
|
||||
|
||||
Once the ansible is installed successfully, verify its version by running the following command
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo ansible --version
|
||||
```
|
||||
|
||||
![Ansible-version-CentOS8][1]
|
||||
|
||||
Above output confirms that Installation is completed successfully on CentOS 8.
|
||||
|
||||
Let’s move to RHEL 8 system
|
||||
|
||||
### Ansible Installation steps on RHEL 8
|
||||
|
||||
If you have a valid RHEL 8 subscription then use following subscription-manager command to enable Ansible Repo,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo subscription-manager repos --enable ansible-2.8-for-rhel-8-x86_64-rpms
|
||||
```
|
||||
|
||||
Once the repo is enabled then execute the following dnf command to install Ansible,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo dnf install ansible -y
|
||||
```
|
||||
|
||||
Once the ansible and its dependent packages are installed then verify ansible version by executing the following command,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo ansible --version
|
||||
```
|
||||
|
||||
### Alternate Way to Install Ansible via pip3 on CentOS 8 / RHEL 8
|
||||
|
||||
If you wish to install Ansible using **pip** (**python’s package manager**) then first install pyhton3 and python3-pip packages using following command,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo dnf install python3 python3-pip -y
|
||||
```
|
||||
|
||||
After pyhthon3 installation, verify its version by running
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ python3 -V
|
||||
Python 3.6.8
|
||||
[root@linuxtechi ~]$
|
||||
```
|
||||
|
||||
Now run below pip3 command to install Ansible,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ pip3 install ansible --user
|
||||
```
|
||||
|
||||
Output,
|
||||
|
||||
![Ansible-Install-pip3-centos8][1]
|
||||
|
||||
Above output confirms that Ansible has been installed successfully using pip3. Let’s see how we can use Ansible
|
||||
|
||||
### How to Use Ansible Automation Tool?
|
||||
|
||||
When we install Ansible using yum or dnf command then its configuration file, inventory file and roles directory created automatically under /etc/ansible folder.
|
||||
|
||||
So, let’s add a group with name “**labservers**” and under this group add ubuntu 18.04 and CentOS 7 System’s ip address in **/etc/ansible/hosts** file
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ sudo vi /etc/ansible/hosts
|
||||
…
|
||||
[labservers]
|
||||
192.168.1.20
|
||||
192.168.1.30
|
||||
…
|
||||
```
|
||||
|
||||
Save & exit file.
|
||||
|
||||
Once the inventory file (/etc/ansible/hosts) is updated then exchange your user’s ssh public keys with remote systems which are part of “labservers” group.
|
||||
|
||||
Let’s first generate your local user’s public and private key using ssh-keygen command,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ ssh-keygen
|
||||
```
|
||||
|
||||
Now exchange public key between the ansible server and its clients using the following command,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ ssh-copy-id root@linuxtechi
|
||||
[root@linuxtechi ~]$ ssh-copy-id root@linuxtechi
|
||||
```
|
||||
|
||||
Now let’s try couple of Ansible commands, first verify the connectivity from Ansible server to its clients using ping module,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ ansible -m ping "labservers"
|
||||
```
|
||||
|
||||
**Note:** If we don’t specify the inventory file in above command then it will refer the default hosts file (i.e /etc/ansible/hosts)
|
||||
|
||||
Output,
|
||||
|
||||
![ansible-ping-module-centos8][1]
|
||||
|
||||
Let’s check kernel version of each client using Ansible shell command,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ ansible -m command -a "uname -r" "labservers"
|
||||
192.168.1.30 | CHANGED | rc=0 >>
|
||||
4.15.0-20-generic
|
||||
192.168.1.20 | CHANGED | rc=0 >>
|
||||
3.10.0-327.el7.x86_64
|
||||
[root@linuxtechi ~]$
|
||||
```
|
||||
|
||||
Use the following ansible command to list all hosts from the inventory file,
|
||||
|
||||
```
|
||||
[root@linuxtechi ~]$ ansible all -i /etc/ansible/hosts --list-hosts
|
||||
hosts (4):
|
||||
192.168.100.1
|
||||
192.168.100.10
|
||||
192.168.1.20
|
||||
192.168.1.30
|
||||
[root@linuxtechi ~]$
|
||||
```
|
||||
|
||||
Use the following ansible command to list only hosts from “labservers” group
|
||||
|
||||
```
|
||||
root@linuxtechi ~]$ ansible labservers -i /etc/ansible/hosts --list-hosts
|
||||
hosts (2):
|
||||
192.168.1.20
|
||||
192.168.1.30
|
||||
[root@linuxtechi ~]$
|
||||
```
|
||||
|
||||
That’s all from this article, we have successfully demonstrated on how to install and use Ansible on CentOS 8 and RHEL 8 System. Please do you share your feedback and comments.
|
||||
|
||||
* [Facebook][4]
|
||||
* [Twitter][5]
|
||||
* [LinkedIn][6]
|
||||
* [Reddit][7]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxtechi.com/install-ansible-centos-8-rhel-8/
|
||||
|
||||
作者:[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]: http://www.linuxtechi.com/wp-content/uploads/2019/11/Install-Ansible-CentOS8-RHEL8.png
|
||||
[3]: http://www.linuxtechi.com/enable-epel-repo-centos8-rhel8-server/
|
||||
[4]: http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.linuxtechi.com%2Finstall-ansible-centos-8-rhel-8%2F&t=How%20to%20Install%20Ansible%20%28Automation%20Tool%29%20on%20CentOS%208%2FRHEL%208
|
||||
[5]: http://twitter.com/share?text=How%20to%20Install%20Ansible%20%28Automation%20Tool%29%20on%20CentOS%208%2FRHEL%208&url=https%3A%2F%2Fwww.linuxtechi.com%2Finstall-ansible-centos-8-rhel-8%2F&via=Linuxtechi
|
||||
[6]: http://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.linuxtechi.com%2Finstall-ansible-centos-8-rhel-8%2F&title=How%20to%20Install%20Ansible%20%28Automation%20Tool%29%20on%20CentOS%208%2FRHEL%208
|
||||
[7]: http://www.reddit.com/submit?url=https%3A%2F%2Fwww.linuxtechi.com%2Finstall-ansible-centos-8-rhel-8%2F&title=How%20to%20Install%20Ansible%20%28Automation%20Tool%29%20on%20CentOS%208%2FRHEL%208
|
162
sources/tech/20191125 How to use loops in awk.md
Normal file
162
sources/tech/20191125 How to use loops in awk.md
Normal file
@ -0,0 +1,162 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to use loops in awk)
|
||||
[#]: via: (https://opensource.com/article/19/11/loops-awk)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
How to use loops in awk
|
||||
======
|
||||
Learn how to use different types of loops to run commands on a record
|
||||
multiple times.
|
||||
![arrows cycle symbol for failing faster][1]
|
||||
|
||||
Awk scripts have three main sections: the optional BEGIN and END functions and the functions you write that are executed on each record. In a way, the main body of an awk script is a loop, because the commands in the functions run for each record. However, sometimes you want to run commands on a record more than once, and for that to happen, you must write a loop.
|
||||
|
||||
There are several kinds of loops, each serving a unique purpose.
|
||||
|
||||
### While loop
|
||||
|
||||
A **while** loop tests a condition and performs commands _while_ the test returns _true_. Once a test returns _false_, the loop is broken.
|
||||
|
||||
|
||||
```
|
||||
#!/bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
# Print the squares from 1 to 10
|
||||
|
||||
i=1;
|
||||
while (i <= 10) {
|
||||
print "The square of ", i, " is ", i*i;
|
||||
i = i+1;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
```
|
||||
|
||||
In this simple example, awk prints the square of whatever integer is contained in the variable _i_. The **while (i <= 10)** phrase tells awk to perform the loop only as long as the value of _i_ is less than or equal to 10. After the final iteration (while _i_ is 10), the loop ends.
|
||||
|
||||
### Do while loop
|
||||
|
||||
The **do while** loop performs commands after the keyword **do**. It performs a test afterward to determine whether the stop condition has been met. The commands are repeated only _while_ the test returns true (that is, the end condition has _not_ been met). If a test fails, the loop is broken because the end condition has been met.
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/awk -f
|
||||
BEGIN {
|
||||
|
||||
i=2;
|
||||
do {
|
||||
print "The square of ", i, " is ", i*i;
|
||||
i = i + 1
|
||||
}
|
||||
while (i < 10)
|
||||
|
||||
exit;
|
||||
}
|
||||
```
|
||||
|
||||
### For loops
|
||||
|
||||
There are two kinds of **for** loops in awk.
|
||||
|
||||
One kind of **for** loop initializes a variable, performs a test, and increments the variable together, performing commands while the test is true.
|
||||
|
||||
|
||||
```
|
||||
#!/bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
for (i=1; i <= 10; i++) {
|
||||
print "The square of ", i, " is ", i*i;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
```
|
||||
|
||||
Another kind of **for** loop sets a variable to successive indices of an array, performing a collection of commands for each index. In other words, it uses an array to "collect" data from a record.
|
||||
|
||||
This example implements a simplified version of the Unix command **uniq**. By adding a list of strings into an array called **a** as a key and incrementing the value each time the same key occurs, you get a count of the number of times a string appears (like the **\--count** option of **uniq**). If you print the keys of the array, you get every string that appears one or more times.
|
||||
|
||||
For example, using the demo file **colours.txt** (from the previous articles):
|
||||
|
||||
|
||||
```
|
||||
name color amount
|
||||
apple red 4
|
||||
banana yellow 6
|
||||
raspberry red 99
|
||||
strawberry red 3
|
||||
grape purple 10
|
||||
apple green 8
|
||||
plum purple 2
|
||||
kiwi brown 4
|
||||
potato brown 9
|
||||
pineapple yellow 5
|
||||
```
|
||||
|
||||
Here is a simple version of **uniq -c** in awk form:
|
||||
|
||||
|
||||
```
|
||||
#! /usr/bin/awk -f
|
||||
|
||||
NR != 1 {
|
||||
a[$2]++
|
||||
}
|
||||
END {
|
||||
for (key in a) {
|
||||
print a[key] " " key
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The third column of the sample data file contains the number of items listed in the first column. You can use an array and a **for** loop to tally the items in the third column by color:
|
||||
|
||||
|
||||
```
|
||||
#! /usr/bin/awk -f
|
||||
|
||||
BEGIN {
|
||||
FS=" ";
|
||||
OFS="\t";
|
||||
print("color\tsum");
|
||||
}
|
||||
NR != 1 {
|
||||
a[$2]+=$3;
|
||||
}
|
||||
END {
|
||||
for (b in a) {
|
||||
print b, a[b]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, you are also printing a header column in the BEFORE function (which always happens only once) prior to processing the file.
|
||||
|
||||
### Loops
|
||||
|
||||
Loops are a vital part of any programming language, and awk is no exception. Using loops can help you control how your awk script runs, what information it's able to gather, and how it processes your data. Our next article will cover switch statements, **continue**, and **next**.
|
||||
|
||||
* * *
|
||||
|
||||
Would you rather listen to this article? It was adapted from an episode of [Hacker Public Radio][2], a community technology podcast by hackers, for hackers.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/loops-awk
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/fail_progress_cycle_momentum_arrow.png?itok=q-ZFa_Eh (arrows cycle symbol for failing faster)
|
||||
[2]: http://hackerpublicradio.org/eps.php?id=2330
|
74
sources/tech/20191125 My top 5 Ansible modules.md
Normal file
74
sources/tech/20191125 My top 5 Ansible modules.md
Normal file
@ -0,0 +1,74 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (My top 5 Ansible modules)
|
||||
[#]: via: (https://opensource.com/article/19/11/ansible-modules)
|
||||
[#]: author: (Mark Phillips https://opensource.com/users/markp)
|
||||
|
||||
My top 5 Ansible modules
|
||||
======
|
||||
Learn how to achieve almost anything with these Ansible modules.
|
||||
![][1]
|
||||
|
||||
When I was growing up, my grandfather had a shed in his garden. He would spend hours in there, making and fixing things. This was way before we had the internet, so I spent a lot of time studying him creating things in that shed. Although the shed was full of many tools, from drills to lathes to electrical gubbins and lots of things I doubt I could identify even today, he made use of only a tiny subset of what he had at hand. Yet there never seemed to be limits to what he could achieve.
|
||||
|
||||
I tell you that story because I feel like my career has been spent in a metaphorical shed. Computers are so many tools, all in a small (virtual?) space. And there are tool sheds within tool sheds—my favourite being Ansible. The recent 2.9 release ships with 3,681 modules! **3,681!** When I first started using Ansible in the summer of 2013, version 1.2.1 had just 113 modules, yet, as [I wrote at the time][2], I could still achieve anything I imagined.
|
||||
|
||||
Modules are the backbone of Ansible, the gears to make light of heavy lifting. They're designed to do one job well, thus realising [the Unix philosophy][3]. This is how we've come to bundle so many of them; Ansible as the conductor of the orchestra now has a lot of instruments at its command.
|
||||
|
||||
Reviewing a Git repository of my Ansible plays and roles over the years reveals that I have used just 35 modules. This small subset was used to build large infrastructures. I wonder what could be achieved with an even smaller subset, though? As I reviewed those 35, I pondered if I could achieve the same results with only five modules at my disposal. So here are my five favourite modules, in a rather tenuous order of precedence.
|
||||
|
||||
### 5. [authorized_key][4]
|
||||
|
||||
Secure shell (SSH) is at the heart of Ansible, at least for almost everything besides Windows. Key (no pun intended) to using SSH efficiently with Ansible is… [keys][5]! Slight aside—there are a lot of very cool things you can do for security with SSH keys. It's worth perusing the **authorized_keys** section of the [sshd manual page][6]. Managing SSH keys can become laborious if you're getting into the realms of granular user access, and although we could do it with either of my next two favourites, I prefer to use the module because it [enables easy management through variables][7].
|
||||
|
||||
### 4. [file][8]
|
||||
|
||||
Besides the obvious function of placing a file somewhere, the **file** module also sets ownership and permissions. I'd say that's a lot of _bang for your buck_ with one module. I'd proffer a substantial portion of security relates to setting permissions too, so the **file** module plays nicely with **authorized_keys**.
|
||||
|
||||
### 3. [template][9]
|
||||
|
||||
There are so many ways to manipulate the contents of files, and I see lots of folk use **[lineinfile][10]**. I've used it myself for small tasks. However, the **template** module is so much clearer because you maintain the entire file for context. My preference is to write Ansible content in such a way that anyone can understand it _easily_—which to me means not making it hard to understand what is happening. Use of **template** means being able to see the entire file you're putting into place, complete with the variables you are using to change pieces.
|
||||
|
||||
### 2. [uri][11]
|
||||
|
||||
Many modules in the current distribution leverage Ansible as an orchestrator. They talk to another service, rather than doing something specific like putting a file into place. Usually, that talking is over HTTP too. In the days before many of these modules existed, you _could_ program an API directly using the **uri** module. It's a powerful access tool, enabling you to do a lot. I wouldn't be without it in my fictitious Ansible shed.
|
||||
|
||||
### 1. [shell][12]
|
||||
|
||||
The joker card in our pack. The Swiss Army Knife. If you're absolutely stuck for how to control something else, use **shell**. Some will argue we're now talking about making Ansible a Bash script—but, I would say it's still better because with the use of the **name** parameter in your plays and roles, you document every step. To me, that's as big a bonus as anything. Back in the days when I was still consulting, I once helped a database administrator (DBA) migrate to Ansible. The DBA wasn't one for change and pushed back at changing working methods. So, to ease into the Ansible way, we called some existing DB management scripts from Ansible using the **shell** module. With an informative **name** statement to accompany the task.
|
||||
|
||||
You can achieve a lot with these five modules. Yes, modules designed to do a specific task will make your life even easier. But with a smidgen of engineering simplicity, you can achieve a lot with very little. Ansible developer Brian Coca is a master at it, and [his tips and tricks talk][13] is always worth a watch.
|
||||
|
||||
* * *
|
||||
|
||||
What do you think about my top five? What five modules would you pick and why, if you were so limited? Let me know in the comments below!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/ansible-modules
|
||||
|
||||
作者:[Mark Phillips][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/markp
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/mandelbrot_set.png?itok=bmPc0np5
|
||||
[2]: http://probably.co.uk/post/puppet-vs-chef-vs-ansible/
|
||||
[3]: https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well
|
||||
[4]: https://docs.ansible.com/ansible/latest/modules/authorized_key_module.html
|
||||
[5]: https://linux.die.net/man/1/ssh-keygen
|
||||
[6]: https://linux.die.net/man/8/sshd
|
||||
[7]: https://github.com/phips/ansible-demos/blob/3bf59df1eb2390b31b5c42333197e2fbb7fec93f/roles/ansible-users/tasks/main.yml#L35
|
||||
[8]: https://docs.ansible.com/ansible/latest/modules/file_module.html
|
||||
[9]: https://docs.ansible.com/ansible/latest/modules/template_module.html
|
||||
[10]: https://docs.ansible.com/ansible/latest/modules/lineinfile_module.html
|
||||
[11]: https://docs.ansible.com/ansible/latest/modules/uri_module.html
|
||||
[12]: https://docs.ansible.com/ansible/latest/modules/shell_module.html
|
||||
[13]: https://www.ansible.com/ansible-tips-and-tricks
|
234
sources/tech/20191125 The many faces of awk.md
Normal file
234
sources/tech/20191125 The many faces of awk.md
Normal file
@ -0,0 +1,234 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The many faces of awk)
|
||||
[#]: via: (https://www.networkworld.com/article/3454979/the-many-faces-of-awk.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
The many faces of awk
|
||||
======
|
||||
The awk command provides a lot more than simply selecting fields from input strings, including pulling out columns of data, printing simple text, evaluating content – even doing math.
|
||||
Thinkstock
|
||||
|
||||
If you only use **awk** when you need to select a specific field from lines of text, you might be missing out on a lot of other services that the command can provide. In this post, we'll look at this simple use along with some of the other things that **awk** can do for you and provide some examples.
|
||||
|
||||
### Plucking out columns of data
|
||||
|
||||
The easiest and most commonly used service that **awk** provides is selecting specific fields from files or from data that is piped to it. With the default of using white space as a field separator, this is very simple.
|
||||
|
||||
[[Get regularly scheduled insights by signing up for Network World newsletters.]][1]
|
||||
|
||||
```
|
||||
$ echo one two three four five | awk ‘{print $4}’
|
||||
four
|
||||
$ who | awk ‘{print $1}’
|
||||
jdoe
|
||||
fhenry
|
||||
```
|
||||
|
||||
White space is any sequence of blanks and tabs. In the commands shown above, **awk** is extracting just the fourth and first fields from the data provided.
|
||||
|
||||
[][2]
|
||||
|
||||
BrandPost Sponsored by HPE
|
||||
|
||||
[Take the Intelligent Route with Consumption-Based Storage][2]
|
||||
|
||||
Combine the agility and economics of HPE storage with HPE GreenLake and run your IT department with efficiency.
|
||||
|
||||
Awk can also pull text from files by just adding the name of the file after the **awk** command.
|
||||
|
||||
```
|
||||
$ awk '{print $1,$5,$NF}' HelenKellerQuote
|
||||
The beautiful heart.
|
||||
```
|
||||
|
||||
In this case, **awk** has picked out the first, fifth and last words in the single line of test.
|
||||
|
||||
The **$NF** specification in the command picks the last piece of text on each line. That is because **NF** represents the number of fields in a line (23) while **$NF** then represents the _value_ of that field ("heart."). The period is included because it's part of the final text string.
|
||||
|
||||
Fields can be printed in any order that you might find useful. In this example, we are rearranging the fields in **date** command output.
|
||||
|
||||
```
|
||||
$ date | awk '{print $4,$3,$2}'
|
||||
2019 Nov 22
|
||||
```
|
||||
|
||||
If you omit the commas between the field designators in an **awk** command, the output will be pushed into a single string.
|
||||
|
||||
```
|
||||
$ date | awk '{print $4 $3 $2}'
|
||||
2019Nov21
|
||||
```
|
||||
|
||||
If you replace the usual commas with hyphens, **awk** will attempt to subtract one field from another – probably not what you intended. It doesn't take the hyphens as characters to be inserted into the print output. Instead, it puts some of its mathematical prowess into play.
|
||||
|
||||
```
|
||||
$ date | awk '{print $4-$3-$2}'
|
||||
1997
|
||||
```
|
||||
|
||||
In this case, it's subtracting 22 (the day of the month) from the year (2019) and simply ignoring "Nov".
|
||||
|
||||
If you want your output to be separated by something other than white space, you can specify your output separator with **OFS** (output field separator) like this:
|
||||
|
||||
```
|
||||
$ date | awk '{OFS="-"; print $4,$3,$2}'
|
||||
2019-Nov-22
|
||||
```
|
||||
|
||||
### Printing simple text
|
||||
|
||||
You can also use **awk** to simply display some text. Of course, if all you want to do is print a line of text, you'd be better off using an **echo** command. On the other hand, as part of an **awk** script, printing some relevant text can be very useful. Here's a practically useless example:
|
||||
|
||||
```
|
||||
$ awk 'BEGIN {print "Hello, World" }'
|
||||
Hello, World
|
||||
```
|
||||
|
||||
Here's a more sensible example in which adding a line of text to label your data can help identify what you're looking at:
|
||||
|
||||
```
|
||||
$ who | awk 'BEGIN {print "Current logins:"} {print $1}'
|
||||
Current logins:
|
||||
shs
|
||||
nemo
|
||||
```
|
||||
|
||||
### Specifying a field separator
|
||||
|
||||
Not all input is going to be separated by white space. If your text is separated by some other character (e.g., commas, colons or semicolons), you can inform **awk** by using the **-F** (input separator) option as shown here:
|
||||
|
||||
```
|
||||
$ cat testfile
|
||||
a:b:c,d:e
|
||||
$ awk -F : '{print $2,$3}' testfile
|
||||
b c,d
|
||||
```
|
||||
|
||||
Here's a more useful example – pulling a field from the colon-separated **/etc/passwd** file:
|
||||
|
||||
```
|
||||
$ awk -F: '{print $1}' /etc/passwd | head -11
|
||||
root
|
||||
daemon
|
||||
bin
|
||||
sys
|
||||
sync
|
||||
games
|
||||
man
|
||||
lp
|
||||
mail
|
||||
news
|
||||
uucp
|
||||
```
|
||||
|
||||
### Evaluating content
|
||||
|
||||
You can also evaluate fields using **awk**. If you, for example, want to list only _user accounts_ in **/etc/passwd**, you can include a test for the 3rd field. Here we're only going after UIDs that are 1000 and above:
|
||||
|
||||
```
|
||||
$ awk -F":" ' $3 >= 1000 ' /etc/passwd
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
shs:x:1000:1000:Sandra Henry-Stocker,,,:/home/shs:/bin/bash
|
||||
nemo:x:1001:1001:Nemo,,,:/home/nemo:/usr/bin/zsh
|
||||
dory:x:1002:1002:Dory,,,:/home/dory:/bin/bash
|
||||
...
|
||||
```
|
||||
|
||||
If you want to add a title for your listing, you can add a BEGIN clause:
|
||||
|
||||
```
|
||||
$ awk -F":" 'BEGIN {print "user accounts:"} $3 >= 1000 ' /etc/passwd
|
||||
user accounts:
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
shs:x:1000:1000:Sandra Henry-Stocker,,,:/home/shs:/bin/bash
|
||||
nemo:x:1001:1001:Nemo,,,:/home/nemo:/usr/bin/zsh
|
||||
dory:x:1002:1002:Dory,,,:/home/dory:/bin/bash
|
||||
```
|
||||
|
||||
If you want more than one line in your title, you can separate your intended output lines with "\n" (newline characters).
|
||||
|
||||
```
|
||||
$ awk -F":" 'BEGIN {print "user accounts\n============="} $3 >= 1000 ' /etc/passwd
|
||||
user accounts
|
||||
=============
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
shs:x:1000:1000:Sandra Henry-Stocker,,,:/home/shs:/bin/bash
|
||||
nemo:x:1001:1001:Nemo,,,:/home/nemo:/usr/bin/zsh
|
||||
dory:x:1002:1002:Dory,,,:/home/dory:/bin/bash
|
||||
```
|
||||
|
||||
### Doing math with awk
|
||||
|
||||
**awk** provides a surprising mathematical ability and can calculate square roots, logs, tangents, etc.
|
||||
|
||||
Here are a couple examples:
|
||||
|
||||
```
|
||||
$ awk 'BEGIN {print sqrt(2019)}'
|
||||
44.9333
|
||||
$ awk 'BEGIN {print log(2019)}'
|
||||
7.61036
|
||||
```
|
||||
|
||||
For more details on **awk**'s mathematical skills, check out [Doing math with awk][3].
|
||||
|
||||
### awk scripts
|
||||
|
||||
You can also write standalone scripts with **awk**. Here's an example that mimics one of the examples provided earlier, but also counts the number of users with accounts on the system.
|
||||
|
||||
```
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
# This line is a comment
|
||||
|
||||
BEGIN {
|
||||
printf "%s\n","User accounts:"
|
||||
print "=============="
|
||||
FS=":"
|
||||
n=0
|
||||
}
|
||||
|
||||
# Now we'll run through the data
|
||||
{
|
||||
if ($3 >= 1000) {
|
||||
print $1
|
||||
n ++
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
print "=============="
|
||||
print n " accounts"
|
||||
}
|
||||
```
|
||||
|
||||
Notice how the BEGIN section, which is run only when the script starts, provides a heading, dictates the field separator and sets up a counter to start with 0. The script also includes an END section which only runs after all the lines in the text provided to the script have been processed. It displays the final count of lines that meet the specification in the middle section (third field is 1,000 or larger)
|
||||
|
||||
A long-standing Unix command, **awk** still provides very useful services and remains one of the reasons that I fell in love with Unix many decades ago.
|
||||
|
||||
To see **awk** in action, click below.
|
||||
|
||||
Join the Network World communities on [Facebook][4] and [LinkedIn][5] to comment on topics that are top of mind.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3454979/the-many-faces-of-awk.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][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.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/newsletters/signup.html
|
||||
[2]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE20773&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[3]: https://www.networkworld.com/article/2974753/doing-math-with-awk.html
|
||||
[4]: https://www.facebook.com/NetworkWorld/
|
||||
[5]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,275 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (5 Commands to Find the IP Address of a Domain in the Linux Terminal)
|
||||
[#]: via: (https://www.2daygeek.com/linux-command-find-check-domain-ip-address/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
5 Commands to Find the IP Address of a Domain in the Linux Terminal
|
||||
======
|
||||
|
||||
This tutorial shows you how to verify a domain name’s or computer name IP address from a Linux terminal.
|
||||
|
||||
This tutorial will allow you to check multiple domains at once.
|
||||
|
||||
You may have already used these commands to verify information.
|
||||
|
||||
However, we will teach you how to use these commands effectively to identify multiple domain IP address information from the Linux terminal.
|
||||
|
||||
This can be done using the following 5 commands.
|
||||
|
||||
* **dig Command:** dig is a flexible cli tool for interrogating DNS name servers.
|
||||
* **host Command:** host is a simple utility for performing DNS lookups.
|
||||
* **nslookup Command:** Nslookup command is used to query Internet domain name servers.
|
||||
* **fping Command:** fping command is used to send ICMP ECHO_REQUEST packets to network hosts.
|
||||
* **ping Command:** ping command is used to send ICMP ECHO_REQUEST packets to network hosts.
|
||||
|
||||
|
||||
|
||||
To test this, we created a file called “domains-list.txt” and added the below domains.
|
||||
|
||||
```
|
||||
# vi /opt/scripts/domains-list.txt
|
||||
|
||||
2daygeek.com
|
||||
magesh.co.in
|
||||
linuxtechnews.com
|
||||
```
|
||||
|
||||
### Method-1: How to Find a IP Address of the Domain Using the dig Command
|
||||
|
||||
**[dig command][1]** stands for “domain information groper”‘ is a powerful and flexible command-line tool for querying DNS name servers.
|
||||
|
||||
It performs DNS lookups and displays the answers that are returned from the name server(s) that were queried.
|
||||
|
||||
Most DNS administrators use dig command to troubleshoot DNS problems because of its flexibility, ease of use and clarity of output.
|
||||
|
||||
It also has a batch mode functionality to read search requests from a file.
|
||||
|
||||
```
|
||||
# dig 2daygeek.com | awk '{print $1,$5}'
|
||||
|
||||
2daygeek.com. 104.27.157.177
|
||||
2daygeek.com. 104.27.156.177
|
||||
```
|
||||
|
||||
Use the following bash script to find the multiple domain’s IP address.
|
||||
|
||||
```
|
||||
# vi /opt/scripts/dig-command.sh
|
||||
|
||||
#!/bin/bash
|
||||
for server in `cat /opt/scripts/domains-list.txt`
|
||||
do echo $server "-"
|
||||
dig $server +short
|
||||
done | paste -d " " - - -
|
||||
```
|
||||
|
||||
Once the above script is added to a file. Set the executable permission for the “dig-command.sh” file.
|
||||
|
||||
```
|
||||
# chmod +x /opt/scripts/dig-command.sh
|
||||
```
|
||||
|
||||
Finally run the bash script to get the output.
|
||||
|
||||
```
|
||||
# sh /opt/scripts/dig-command.sh
|
||||
|
||||
2daygeek.com - 104.27.156.177 104.27.157.177
|
||||
magesh.co.in - 104.18.35.52 104.18.34.52
|
||||
linuxtechnews.com - 104.27.144.3 104.27.145.3
|
||||
```
|
||||
|
||||
If you want to run the above script in one line, use the following script.
|
||||
|
||||
```
|
||||
# for server in 2daygeek.com magesh.co.in linuxtechnews.com; do echo $server "-"; dig $server +short; done | paste -d " " - - -
|
||||
```
|
||||
|
||||
Alternatively, you can use the following shell script to find the IP address of the multiple domain.
|
||||
|
||||
```
|
||||
# for server in 2daygeek.com magesh.co.in linuxtechnews.com; do dig $server | awk '{print $1,$5}'; done
|
||||
|
||||
2daygeek.com. 104.27.157.177
|
||||
2daygeek.com. 104.27.156.177
|
||||
magesh.co.in. 104.18.34.52
|
||||
magesh.co.in. 104.18.35.52
|
||||
linuxtechnews.com. 104.27.144.3
|
||||
linuxtechnews.com. 104.27.145.3
|
||||
```
|
||||
|
||||
### Method-2: How to Find a Domain’s IP Address Using the host Command
|
||||
|
||||
**[Host Command][2]** is a simple CLI application to perform **[DNS lookup][3]**.
|
||||
|
||||
It is commonly used to convert names to IP addresses and vice versa.
|
||||
|
||||
When no arguments or options are given, host prints a short summary of its command line arguments and options.
|
||||
|
||||
You can view all types of records in the domain by adding a specific option or type of record in the host command.
|
||||
|
||||
```
|
||||
# host 2daygeek.com | grep "has address" | sed 's/has address/-/g'
|
||||
|
||||
2daygeek.com - 104.27.157.177
|
||||
2daygeek.com - 104.27.156.177
|
||||
```
|
||||
|
||||
Use the following bash script to find the multiple domain’s IP address.
|
||||
|
||||
```
|
||||
# vi /opt/scripts/host-command.sh
|
||||
|
||||
for server in `cat /opt/scripts/domains-list.txt`
|
||||
do host $server | grep "has address" | sed 's/has address/-/g'
|
||||
done
|
||||
```
|
||||
|
||||
Once the above script is added to a file. Set the executable permission for the “host-command.sh” file.
|
||||
|
||||
```
|
||||
# chmod +x /opt/scripts/host-command.sh
|
||||
```
|
||||
|
||||
Finally run the bash script to get the output.
|
||||
|
||||
```
|
||||
# sh /opt/scripts/host-command.sh
|
||||
|
||||
2daygeek.com - 104.27.156.177
|
||||
2daygeek.com - 104.27.157.177
|
||||
magesh.co.in - 104.18.35.52
|
||||
magesh.co.in - 104.18.34.52
|
||||
linuxtechnews.com - 104.27.144.3
|
||||
linuxtechnews.com - 104.27.145.3
|
||||
```
|
||||
|
||||
### Method-3: How to Find the IP Address of a Domain Using the nslookup Command
|
||||
|
||||
**[nslookup command][4]** is a program for querying Internet **[domain name servers (DNS)][5]**.
|
||||
|
||||
nslookup has two modes, which are interactive and interactive.
|
||||
|
||||
Interactive mode allows the user to query name servers for information about various hosts and domains or to print a list of hosts in a domain.
|
||||
|
||||
Non-interactive mode is used to print just the name and requested information for a host or domain.
|
||||
|
||||
It is a network administration tool that helps diagnose and resolve DNS related issues.
|
||||
|
||||
```
|
||||
# nslookup -q=A 2daygeek.com | tail -n+4 | sed -e '/^$/d' -e 's/Address://g' | grep -v 'Name|answer' | xargs -n1
|
||||
|
||||
104.27.157.177
|
||||
104.27.156.177
|
||||
```
|
||||
|
||||
Use the following bash script to find the multiple domain’s IP address.
|
||||
|
||||
```
|
||||
# vi /opt/scripts/nslookup-command.sh
|
||||
|
||||
#!/bin/bash
|
||||
for server in `cat /opt/scripts/domains-list.txt`
|
||||
do echo $server "-"
|
||||
nslookup -q=A $server | tail -n+4 | sed -e '/^$/d' -e 's/Address://g' | grep -v 'Name|answer' | xargs -n1 done | paste -d " " - - -
|
||||
```
|
||||
|
||||
Once the above script is added to a file. Set the executable permission for the “nslookup-command.sh” file.
|
||||
|
||||
```
|
||||
# chmod +x /opt/scripts/nslookup-command.sh
|
||||
```
|
||||
|
||||
Finally run the bash script to get the output.
|
||||
|
||||
```
|
||||
# sh /opt/scripts/nslookup-command.sh
|
||||
|
||||
2daygeek.com - 104.27.156.177 104.27.157.177
|
||||
magesh.co.in - 104.18.35.52 104.18.34.52
|
||||
linuxtechnews.com - 104.27.144.3 104.27.145.3
|
||||
```
|
||||
|
||||
### Method-4: How to Find a Domain’s IP Address Using the fping Command
|
||||
|
||||
**[fping command][6]** is a program such as ping, which uses the Internet Control Message Protocol (ICMP) echo request to determine whether a target host is responding.
|
||||
|
||||
fping differs from ping because it allows users to ping any number of host in parallel. Also, hosts can be entered from a text file.
|
||||
|
||||
fping sends an ICMP echo request, moves the next target in a round-robin fashion, and does not wait until the target host responds.
|
||||
|
||||
If a target host replies, it is noted as active and removed from the list of targets to check; if a target does not respond within a certain time limit and/or retry limit it is designated as unreachable.
|
||||
|
||||
```
|
||||
# fping -A -d 2daygeek.com magesh.co.in linuxtechnews.com
|
||||
|
||||
104.27.157.177 (104.27.157.177) is alive
|
||||
104.18.35.52 (104.18.35.52) is alive
|
||||
104.27.144.3 (104.27.144.3) is alive
|
||||
```
|
||||
|
||||
### Method-5: How to Find the IP Address of the Domain Using the ping Command
|
||||
|
||||
**[ping command][6]** stands for (Packet Internet Groper) command is a networking utility that used to test the target of a host availability/connectivity on an Internet Protocol (IP) network.
|
||||
|
||||
It’s verify a host availability by sending Internet Control Message Protocol (ICMP) Echo Request packets to the target host and waiting for an ICMP Echo Reply.
|
||||
|
||||
It summarize statistical results based on the packets transmitted, packets received, packet loss, typically including the min/avg/max times.
|
||||
|
||||
```
|
||||
# ping -c 2 2daygeek.com | head -2 | tail -1 | awk '{print $5}' | sed 's/[(:)]//g'
|
||||
|
||||
104.27.157.177
|
||||
```
|
||||
|
||||
Use the following bash script to find the multiple domain’s IP address.
|
||||
|
||||
```
|
||||
# vi /opt/scripts/ping-command.sh
|
||||
|
||||
#!/bin/bash
|
||||
for server in `cat /opt/scripts/domains-list.txt`
|
||||
do echo $server "-"
|
||||
ping -c 2 $server | head -2 | tail -1 | awk '{print $5}' | sed 's/[(:)]//g'
|
||||
done | paste -d " " - -
|
||||
```
|
||||
|
||||
Once the above script is added to a file. Set the executable permission for the “dig-command.sh” file.
|
||||
|
||||
```
|
||||
# chmod +x /opt/scripts/ping-command.sh
|
||||
```
|
||||
|
||||
Finally run the bash script to get the output.
|
||||
|
||||
```
|
||||
# sh /opt/scripts/ping-command.sh
|
||||
|
||||
2daygeek.com - 104.27.156.177
|
||||
magesh.co.in - 104.18.35.52
|
||||
linuxtechnews.com - 104.27.144.3
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/linux-command-find-check-domain-ip-address/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.2daygeek.com/author/magesh/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.2daygeek.com/dig-command-check-find-dns-records-lookup-linux/
|
||||
[2]: https://www.2daygeek.com/linux-host-command-check-find-dns-records-lookup/
|
||||
[3]: https://www.2daygeek.com/category/dns-lookup/
|
||||
[4]: https://www.2daygeek.com/nslookup-command-check-find-dns-records-lookup-linux/
|
||||
[5]: https://www.2daygeek.com/check-find-dns-records-of-domain-in-linux-terminal/
|
||||
[6]: https://www.2daygeek.com/how-to-use-ping-fping-gping-in-linux/
|
@ -0,0 +1,122 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (App Highlight: Penguin Subtitle Player for Adding Subtitles to Online Videos)
|
||||
[#]: via: (https://itsfoss.com/penguin-subtitle-player/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
App Highlight: Penguin Subtitle Player for Adding Subtitles to Online Videos
|
||||
======
|
||||
|
||||
I must confess. I am addicted to subtitles. It helps me understand the dialogues completely, specially if some dialogues are in a different accent or in a different language.
|
||||
|
||||
This has led to a habit of watching online videos with subtitles.
|
||||
|
||||
While streaming services like Netflix and Amazon Prime provide subtitles for their content, the same is not true for all the websites.
|
||||
|
||||
I often discover interesting content that are on YouTube, Dailymotion or other websites. And that becomes a problem because most of the time, these videos don’t have subtitles.
|
||||
|
||||
The good news is that you have the possibility to watch any online video content with subtitles and I’ll share that neat little trick with you in this article.
|
||||
|
||||
### Watch any online video with subtitles using Penguin subtitle player
|
||||
|
||||
![][1]
|
||||
|
||||
What the heck is a Subtitle player?
|
||||
|
||||
The [open source video players][2] you use allow you to add subtitles. Players like [VLC allow you to download subtitles automatically][3].
|
||||
|
||||
But they are video player and their main task is to play video.
|
||||
|
||||
A subtitle player on the other hand has only one task and that is to play subtitles. Confused? Let me explain.
|
||||
|
||||
A subtitle player basically provides an interface where you can add subtitle file and play the subtitles with a semi transparent background. The trick here is that this player will be visible all the time on top of any other application.
|
||||
|
||||
So if you are running the subtitle player even while using a website, it will still be visible. That actually is the trick to watch any online video with subtitles.
|
||||
|
||||
![An external subtitle playing on top of YouTube video][4]
|
||||
|
||||
All you have to do is to find appropriate subtitles from an online website like OpenSubtitles and add it to the subtitle player. Now open the website where you want to watch the video. Play it full screen (if that option is available) and it will feel like that the subtitles are part of the video itself.
|
||||
|
||||
![][5]
|
||||
|
||||
#### Install Penguin subtitle player
|
||||
|
||||
[Penguin][6] is a free and open source subtitle player. It is available for Linux, macOS and Windows.
|
||||
|
||||
If you are using Ubuntu-based distribution, you can [use this PPA][7] to easily install Penguin subtitle player.
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:nilarimogard/webupd8
|
||||
sudo apt update
|
||||
sudo apt install penguin-subtitle-player
|
||||
```
|
||||
|
||||
For other Linux distributions, Windows and macOS, you can download the installer files from SourceForge:
|
||||
|
||||
[Download Penguin Subtitle Player][8]
|
||||
|
||||
#### Using Penguin subtitle player
|
||||
|
||||
Once you have installed the application, look for it in the menu and start it. You’ll see an interface like this:
|
||||
|
||||
![Penguin Subtitle Player Interface][9]
|
||||
|
||||
If you have already downloaded the .srt subtitle file, you can add it to the player by clicking the folder icon.
|
||||
|
||||
![Add Subtitle In Penguin Subtitle Player][10]
|
||||
|
||||
You can play/pause the subtitles, skip it to a new time. This helps in adjusting the subtitles with the video.
|
||||
|
||||
![Adjust Subtitle In Penguin Subtitle Player][11]
|
||||
|
||||
You can also tweak the appearance of the subtitles and subtitle player.
|
||||
|
||||
![Configure Penguin Subtitle Player][12]
|
||||
|
||||
You also have the option to change the fonts, font size and color of the subtitle text. You may also increase or decrease the transparency and color of the background.
|
||||
|
||||
![Config Options In Penguin Subtitle Player][13]
|
||||
|
||||
You can also resize the subtitle player interface and move it around anywhere on the screen.
|
||||
|
||||
#### Keep in mind
|
||||
|
||||
There are a few things to keep in mind while using Penguin subtitle player.
|
||||
|
||||
Not all video files and subtitle files are made for each other. Subtitle synchronization is a common problem so you’ll have to make sure that the subtitle you downloaded is best suited for the video you want to play.
|
||||
|
||||
Most video players, even the one embedded on the websites, allow to pause and play the video with the space key. Unfortunately, there is no keyboard shortcut to pause the Penguin subtitle player. In other words, you cannot pause the video and the subtitle player in one keystroke.
|
||||
|
||||
With this much configuration, you should be set for watching online videos with subtitles.
|
||||
|
||||
I hope you enjoy this nifty little open source application. Do let me know whether you find it useful or not.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/penguin-subtitle-player/
|
||||
|
||||
作者:[Abhishek Prakash][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://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/Add_subtitle_online_videos.png?ssl=1
|
||||
[2]: https://itsfoss.com/video-players-linux/
|
||||
[3]: https://itsfoss.com/download-subtitles-automatically-vlc-media-player-ubuntu/
|
||||
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/penguin_subtitle_player.jpg?ssl=1
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2015/05/Penguin_Subtitle_Player.jpg?ssl=1
|
||||
[6]: https://github.com/carsonip/Penguin-Subtitle-Player
|
||||
[7]: https://itsfoss.com/ppa-guide/
|
||||
[8]: https://sourceforge.net/projects/penguinsubtitleplayer/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/penguin-subtitle-player-interface.jpg?ssl=1
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/add_subtitle_in_penguin_subtitle_player.jpg?ssl=1
|
||||
[11]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/adjust_subtitle_in_penguin_subtitle_player.jpg?ssl=1
|
||||
[12]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/configure_penguin_subtitle_player.jpg?ssl=1
|
||||
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/11/config_options_in_penguin_subtitle_player.jpg?ssl=1
|
Loading…
Reference in New Issue
Block a user