mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-08-23 04:03:29 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Linux Lite 5.0 Released With UEFI Support & Other Major Improvements)
|
||||
[#]: via: (https://itsfoss.com/linux-lite-5-release/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Linux Lite 5.0 Released With UEFI Support & Other Major Improvements
|
||||
======
|
||||
|
||||
Linux Lite is one of the [best Linux distributions suitable for Windows users][1]. Not just limited to that, it’s also one of the most preferred [lightweight Linux distributions][2] available.
|
||||
|
||||
Linux Lite 4.x series based on Ubuntu 18.04 was good but it didn’t have [UEFI support][3]. But, now that Linux Lite 5.0 has finally arrived based on [Ubuntu 20.04][4] and I’m excited to see the changes!
|
||||
|
||||
In this article, we’ll take a look at what’s new in Linux Lite 5.0.
|
||||
|
||||
### Linux Lite 5.0: Key Changes
|
||||
|
||||
![][5]
|
||||
|
||||
With Linux Lite 5.0, they have finally added the support for [UEFI][3] along with numerous significant improvements. Let’s take a brief look at what has changed:
|
||||
|
||||
#### UEFI Support
|
||||
|
||||
Linux Lite 5.0 supports UEFI out-of-the-box. However, they recommend disabling the [Secure Boot][6] feature even though it should work with that.
|
||||
|
||||
![][7]
|
||||
|
||||
You can take a look at one of their [forum threads][8] to understand more about it. Not to mention, you can also find more information about it in the new inbuilt **Help Manual**.
|
||||
|
||||
#### Ubuntu-based distro with no hidden telemetry
|
||||
|
||||
If you were looking for a Linux distribution that’s based on Ubuntu but without any hidden telemetry, Linux Lite 5.0 seemts to be the perfect option.
|
||||
|
||||
In the [release announcement][9], they mentioned it in the changelog along with a screenshot that you can see here:
|
||||
|
||||
![][10]
|
||||
|
||||
#### GUFW Firewall replaced by firewallId
|
||||
|
||||
You might have read about [setting up a firewall using GUFW on Linux][11] but starting with Linux Lite 5.0, it has been replaced by [firewallId][12].
|
||||
|
||||
![][13]
|
||||
|
||||
It seems that [GUFW][14] isn’t as configurable as firewallId. Hence, they decided to replace it.
|
||||
|
||||
By default, it is disabled. But, you can choose to enable it by following one of the tutorials in the **Help Manual**.
|
||||
|
||||
#### Latest Whisker Menu
|
||||
|
||||
![][15]
|
||||
|
||||
[Whisker Menu][16] has been updated to the latest package (v2.4.4) available. In addition to the update, you can also notice that “**Install Updates**” is now pinned to the favorites section.
|
||||
|
||||
#### HiDPI Settings
|
||||
|
||||
![][17]
|
||||
|
||||
You will find it very easy to utilize the HiDPI settings from the **Settings menu** if you need it.
|
||||
|
||||
#### XFCE Screensaver Added
|
||||
|
||||
With Linux Lite 5.0, you will also notice the addition of [XFCE screensaver][18] program — which is disabled by default.
|
||||
|
||||
![][19]
|
||||
|
||||
It’s a simple addition that should be useful for users who always wanted a screensaver app and the ability to tweak it.
|
||||
|
||||
### Other Important Improvements
|
||||
|
||||
In addition to the key highlights mentioned above, there are several other changes that should come in handy for Linux Lite 5.0 users. I’ve listed some of them here:
|
||||
|
||||
* [Mousepad][20] replaces [Leafpad][21]
|
||||
* New update notification
|
||||
* Integrity Check during live boot
|
||||
* Major improvements to the **Help Manual**
|
||||
* Added Chromium as a Snap package
|
||||
* New Logout options
|
||||
* Lite Welcome screen and Lite User Manager now updated to GTK3 and Python3.
|
||||
* New options added to the Welcome screen: **Select Dark or Light Theme, UEFI & Secure Boot, Feedback**
|
||||
* Improved Lite Widget
|
||||
|
||||
|
||||
|
||||
You can find a list of detailed changes in their [official announcement post][9] if you want to explore more about it.
|
||||
|
||||
### Wrapping Up
|
||||
|
||||
I think Linux Lite 5.0 is better than ever and with all the recent additions it’s also going to be a fantastic option for a lot of new Linux users.
|
||||
|
||||
What do you think about Linux Lite 5.0? Let me know your thoughts in the comments down below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/linux-lite-5-release/
|
||||
|
||||
作者:[Ankush Das][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/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/windows-like-linux-distributions/
|
||||
[2]: https://itsfoss.com/lightweight-linux-beginners/
|
||||
[3]: https://help.ubuntu.com/community/UEFI
|
||||
[4]: https://itsfoss.com/ubuntu-20-04-release-features/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/06/linux-lite-5.jpg?ssl=1
|
||||
[6]: https://en.wikipedia.org/wiki/Hardware_restriction#Secure_boot
|
||||
[7]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/06/linux-lite-uefi.png?ssl=1
|
||||
[8]: https://www.linuxliteos.com/forums/uefi-secure-boot/
|
||||
[9]: https://www.linuxliteos.com/forums/release-announcements/linux-lite-5-0-final-released/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/linux-lite-5-telemetry.png?ssl=1
|
||||
[11]: https://itsfoss.com/set-up-firewall-gufw/
|
||||
[12]: https://firewalld.org/
|
||||
[13]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/06/linux-lite-5-firewall.jpg?ssl=1
|
||||
[14]: http://gufw.org/
|
||||
[15]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/06/whisker-menu-linux-lite.jpg?ssl=1
|
||||
[16]: https://gottcode.org/xfce4-whiskermenu-plugin/
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/linux-lite-5-hidpi.png?ssl=1
|
||||
[18]: https://docs.xfce.org/apps/screensaver/start
|
||||
[19]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/linux-lite-5-screensaver.jpg?ssl=1
|
||||
[20]: https://salsa.debian.org/xfce-team/apps/mousepad
|
||||
[21]: https://tarot.freeshell.org/leafpad/
|
||||
@@ -0,0 +1,59 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Red Hat: Holding Its Own and Fueling Open Source Innovation)
|
||||
[#]: via: (https://www.linux.com/articles/red-hat-holding-its-own-and-fueling-open-source-innovation/)
|
||||
[#]: author: (Swapnil Bhartiya https://www.linux.com/author/swapnil/)
|
||||
|
||||
Red Hat: Holding Its Own and Fueling Open Source Innovation
|
||||
======
|
||||
|
||||
When IBM acquired Red Hat for $34 billion in 2019, it was considered the industry’s largest software acquisition. The synergy between the two companies led them to become one of the leading hybrid multi-cloud providers globally.
|
||||
|
||||
In most acquisitions, the acquired entity sometimes loses momentum and sheds some of its original luster. This does not seem to be the case with Red Hat.
|
||||
|
||||
**Distinct Identity**
|
||||
“I would define it as a separate company and that’s how we run it,” affirms Paul Cormier, President & CEO of Red Hat, who is credited with conceptualizing the company’s open hybrid cloud platform.
|
||||
|
||||
“We set our own strategy, we set our own road maps. It’s completely up to us. We have stayed as a self-contained company. Red Hat still has all the pieces to be a separate company: its own Engineering, product lines, back office, HR, Legal, and Finance. It’s very much like VMware is to Dell, or LinkedIn is to Microsoft,” he explains.
|
||||
|
||||
Cormier believes it’s important to have separate identities for partner ecosystems to thrive.
|
||||
|
||||
“We are talking about integrating Arc with OpenShift. IBM didn’t even know this was happening as we had kept it confidential,” he says.
|
||||
|
||||
Microsoft’s Azure Arc is a management tool for hybrid cloud application infrastructures, while OpenShift is a family of containerization software developed by Red Hat.
|
||||
|
||||
“We’re big on Intel platforms. We’re also big on IBM Z, IBM I, IBM P. Since we support Intel in Red Hat Enterprise Linux (REL), we know their road maps long before they’re implemented. However, we have to show Intel that we would not give away their secrets to IBM. This is the most important reason that we must remain separate so that those partner ecosystems remain,” he says.
|
||||
|
||||
**Linux: The Innovation Engine**
|
||||
Cormier points out that what makes Red Hat very unique is its completely open-source software development model.
|
||||
|
||||
“That’s our development model. Open source is not a thing — it’s an action,” he says.
|
||||
|
||||
Underlining the importance of Linux, he explains that “Linux went by Unix a long time ago in terms of features, function, and performance. However, Linux was so available that eventually, it became the innovation engine. All the technologies today — on the infrastructure and the development side, on the tools side — they are all built-in and around Linux. OpenShift is still a Linux platform. Its containers are Linux. All the innovation is now around that.”
|
||||
|
||||
Cormier is also confident of meeting the demand of customers adopting hybrid cloud.
|
||||
|
||||
“For us, it doesn’t matter whether it’s 20% on-premise, 20% in the cloud and 80% on-premise, or 60/40 or 50/50 — it’s still a hybrid world. I can’t predict if the COVID thing is going to push people to the cloud more quickly or more slowly, but we don’t care. It doesn’t matter. For us, it’s the same value proposition,” he avers.
|
||||
|
||||
**Virtualization meets Kubernetes **
|
||||
Red Hat is now working on bringing VMs into the Kubernetes architecture.
|
||||
|
||||
“As opposed to some of our competitors that are trying to bring containers back to their world, we’re moving in the other direction. We are working on advanced cluster management on Kubernetes. As customers increasingly go hybrid, having OpenShift with containers running in different places will help them easily manage across clusters,” Cormier says.
|
||||
|
||||
“We’re also focusing on telco 5G use cases on the OpenShift platform. We’re doing a lot of work with Verizon and the other telcos,” he adds.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/articles/red-hat-holding-its-own-and-fueling-open-source-innovation/
|
||||
|
||||
作者:[Swapnil Bhartiya][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.linux.com/author/swapnil/
|
||||
[b]: https://github.com/lujun9972
|
||||
@@ -1,198 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Remove Files Older than N Days Using Tmpwatch/Tmpreaper on Linux)
|
||||
[#]: via: (https://www.2daygeek.com/how-to-remove-files-older-than-n-days-using-tmpwatch-tmpreaper-on-linux/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
How to Remove Files Older than N Days Using Tmpwatch/Tmpreaper on Linux
|
||||
======
|
||||
|
||||
You may have missed deleting files that are no longer needed on your computer in some directory.
|
||||
|
||||
This can be “Download” or any other directory.
|
||||
|
||||
It may have grown up over a period of time.
|
||||
|
||||
If you have enough storage, you should remove them, as this will slow down your system when you list files.
|
||||
|
||||
Also, it can be clumsy when you have thousands of files in one directory.
|
||||
|
||||
It is very difficult to find a file in a specific directory when you do not know the file name you want to check.
|
||||
|
||||
We can do this by using the find command with some combination, and we have written an article about this in the past.
|
||||
|
||||
* [**Bash Script to Delete Files/Folders Older Than “X” Days in Linux**][1]
|
||||
* [**How To Find And Delete Files Older Than “X” Days And “X” Hours In Linux?**][1]
|
||||
* [**How To Automatically Delete Or Clean Up /tmp Folder Contents In Linux?**][1]
|
||||
|
||||
|
||||
|
||||
Today we are going to show you how to achieve this using the Tmpwatch utility on Linux.
|
||||
|
||||
### What is Tmpwatch
|
||||
|
||||
Tmpwatch recursively removes files that have not been accessed for a specified period of time in the specified directories.
|
||||
|
||||
Typically, it is used to automatically clean directories used for temporary file systems, such as / tmp and /var/tmp.
|
||||
|
||||
It only remove empty directories, regular files, and symbolic links.
|
||||
|
||||
It doesn’t switch to other file systems, and avoids the “lost+found” directory belonging to the root user.
|
||||
|
||||
By default, tmpwatch deletes files based on their atime (access time), not their mtime (conversion time).
|
||||
|
||||
You can change this behavior by adding other parameters in the tmpwatch command.
|
||||
|
||||
**WARNING:** Please do not run “tmpwatch” or “tmpreaper” in “/” because there is no mechanism in the program to protect against this.
|
||||
|
||||
### How to Install Tmpwatch on Linux
|
||||
|
||||
Tmpwatch can be installed as follows from the distribution official repository.
|
||||
|
||||
For **RHEL/CentOS 6** systems, use the **[yum command][2]** to install Tmpwatch.
|
||||
|
||||
```
|
||||
$ sudo yum install -y tmpwatch
|
||||
```
|
||||
|
||||
For **Debian** and **Ubuntu** systems, use the **[apt command][3]** or **[apt-get command][4]** to install Tmpreaper.
|
||||
|
||||
```
|
||||
$ sudo apt-get install tmpreaper
|
||||
```
|
||||
|
||||
For **openSUSE** systems, use the **[zypper command][5]** to install Tmpwatch.
|
||||
|
||||
```
|
||||
$ sudo zypper install -y tmpwatch
|
||||
```
|
||||
|
||||
For **Fedora** systems, use the **[dnf command][6]** to install Tmpwatch.
|
||||
|
||||
```
|
||||
$ sudo dnf install -y tmpwatch
|
||||
```
|
||||
|
||||
**Make a note:** If you are using Debian-based systems, use “tmpreaper” instead of tmpwatch. All examples will work as expected.
|
||||
|
||||
### Understanding Key Options and Arguments
|
||||
|
||||
* **atime** (File Last Access Time) – Access time shows the last time the data from a file was accessed by any of the process such as command or script, etc,.
|
||||
* **mtime** (File Last Modify Time) – mtime shows when you modify a file contents or save a file. Most of the times ctime and mtime will be the same, unless the file attributes are updated.
|
||||
* **ctime** (File Last Change Time) – ctime shows when your file metadata got changed. It means when the file attributes are changed like ownership or group, etc,.
|
||||
* **dirmtime** (Directory Last modification time) – dirmtime shows when your directory last modified.
|
||||
|
||||
|
||||
|
||||
The time parameter defines the threshold for removing files.
|
||||
|
||||
* d – for days
|
||||
* h – for hours
|
||||
* m – for minutes
|
||||
* s – for seconds
|
||||
|
||||
|
||||
|
||||
### How to Removes Files That Haven’t Been Accessed for a Period of Time Using the Tmpwatch Command
|
||||
|
||||
As I said at the beginning of the article, Tmpwatch deletes files by default (atime) depending on the time of access to the files. Also, since hours are the default parameter, you do not need to add the suffix to time if the action is performed using the hour unit.
|
||||
|
||||
For example, run the command below to recursively remove files that have not been accessed for the past 5 hours.
|
||||
|
||||
```
|
||||
# tmpwatch 5 /tmp
|
||||
```
|
||||
|
||||
Run the command below to delete files that have not been modified for the last 10 hours. If you want to delete files using mtime, you need to add the “-m” option with the tmpwatch command.
|
||||
|
||||
```
|
||||
# tmpwatch -m 10 /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### How to Delete Files That Haven’t Been Accessed more than “X” Days Using the Tmpwatch Command
|
||||
|
||||
If you want to delete files using days, you need to add the suffix “d”. The example below deletes files older than 30 days.
|
||||
|
||||
```
|
||||
# tmpwatch 30d /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### How to Delete All Files That Haven’t Been Accessed for a Period of Time Using the Tmpwatch Command
|
||||
|
||||
The below command removes all file types, not just regular files, symbolic links and directories based on mtime.
|
||||
|
||||
```
|
||||
# tmpwatch -am 12 /tmp
|
||||
```
|
||||
|
||||
### How to Exclude a Directory with Tmpwatch
|
||||
|
||||
The below command will delete all files and excludes directories that haven’t been modified for the past 10 hours.
|
||||
|
||||
```
|
||||
# tmpwatch -am 10 --nodirs /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### How to Exclude a Specific Path with Tmpwatch
|
||||
|
||||
The command below will delete all files except the directory below which has not been modified for the past 10 hours.
|
||||
|
||||
```
|
||||
# tmpwatch -am 10 --exclude=/home/daygeek/Downloads/Movies /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### How to Exclude Specific Pattern with Tmpwatch
|
||||
|
||||
The command below will delete all files except the Pattern below which has not been modified for the past 10 hours.
|
||||
|
||||
```
|
||||
# tmpwatch -am 10 --exclude-pattern='*.pdf' /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### How to Perform Dry Run with Tmpwatch Command
|
||||
|
||||
Run the below command if you want to perform dry run.
|
||||
|
||||
```
|
||||
# tmpwatch -t 5h /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### How to Setup a Cronjob to Delete files Periodically Using Tmpwatch
|
||||
|
||||
By default it leaves a **[cronjob][7]** file under the **“/etc/cron.daily/tmpreaper”** directory. This cronjob works according to the configuration file located in **“/etc/timereaper.conf”**. You can customize the file according to your needs.
|
||||
|
||||
It runs once a day and deletes files older than 7 days.
|
||||
|
||||
Alternatively, if you would like to perform an action routinely, you can manually add a conjob based on your needs.
|
||||
|
||||
```
|
||||
# crontab -e
|
||||
|
||||
0 10 * * * /usr/sbin/tmpwatch 15d /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
The above cronjob will delete files that are older than 15 days daily at 10AM.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/how-to-remove-files-older-than-n-days-using-tmpwatch-tmpreaper-on-linux/
|
||||
|
||||
作者:[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/bash-script-to-delete-files-folders-older-than-x-days-in-linux/
|
||||
[2]: https://www.2daygeek.com/linux-yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[3]: https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[4]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[5]: https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[6]: https://www.2daygeek.com/linux-dnf-command-examples-manage-packages-fedora-centos-rhel-systems/
|
||||
[7]: https://www.2daygeek.com/linux-crontab-cron-job-to-schedule-jobs-task/
|
||||
@@ -1,149 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (20 productivity tools for the Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/20/6/productivity-tools-linux-terminal)
|
||||
[#]: author: (Alan Smithee https://opensource.com/users/alansmithee)
|
||||
|
||||
20 productivity tools for the Linux terminal
|
||||
======
|
||||
Try some of these open source tools. Get more done.
|
||||
![Computer screen with files or windows open][1]
|
||||
|
||||
Many of us, admittedly, only use computers because they're fun. But some people use computers to get stuff done, and their theory is computers are supposed to make things faster, better, and more organized. In practice, though, computers don't necessarily improve our lives without a little manual reconfiguration to match our individual work styles.
|
||||
|
||||
[Kevin Sonney][2] likes to design systems, not just for networks but for improving his own workday, and this year he covered 18 different productivity tools in a series of 20 articles. This article gets all of Kevin's favorite tools in one place and provides a quick summary of what each one can do for you.
|
||||
|
||||
### File sync
|
||||
|
||||
![][3]
|
||||
|
||||
Important files deserve to be managed carefully.
|
||||
|
||||
* [Syncthing][4] is a way for you to keep files on different devices in sync with one another. A _device_ can be a Linux, Windows, or Mac computer, a server, an Android tablet or phone, and so on, and the files can be any file you want to keep updated across many machines. Syncthing is lightweight and peer-to-peer, so you don't need to pay for a service, you don't need a third-party server, and it's fast.
|
||||
* Synchronization is one thing, but sometimes you also need help dealing with the files you have. Say you want an application to behave differently depending on whether it's being used as a graphical application or as a console application. You could change the config file between, say, `.foo-gui` and ****`.foo-term` by changing which its symlink points to. Doing that manually is entirely possible, but it could be scripted, or you could just use [GNU Stow][5] instead.
|
||||
|
||||
|
||||
|
||||
### Email management
|
||||
|
||||
![][6]
|
||||
|
||||
We all depend on email and inboxes, but few of us seem to be comfortable with how we manage it. If you're inclined to working in the terminal, why not stay in the terminal for email? It's one thing to check and send email from a terminal, but it's even more exciting to organize your email that way. If you're a typist by trade and scripter by nature, check out some of these tools.
|
||||
|
||||
* I use [OfflineIMAP][7] every day to sync work email to my laptop for viewing in Mutt. It's a specific tool that does exactly one thing: it ensures that a local copy of your email inbox mirrors your remote inbox. It's relatively easy to set up and schedule with [cron][8], and then you can forget it exists. Easy and worth every minute you spend fighting with IMAP.
|
||||
* [Notmuch][9] indexes, tags, and searches mail messages. If you have a problem with your inbox, it takes _not much_ effort to remedy it.
|
||||
* [Vim][10] can check and send email and manage your calendar.
|
||||
* [Emacs][11], of course, also does email and calendaring.
|
||||
|
||||
|
||||
|
||||
### Calendars and contacts
|
||||
|
||||
![][12]
|
||||
|
||||
Every Linux system I've ever used comes with the `cal` command installed. This is a handy little calendar for the terminal, and it's a great quick reference. However, it's hardly what you'd call a calendaring application. The [iCalendar][13] specification (no relation to Apple's old desktop calendar) provides rich shared calendaring functionality, and while `.ics` appointments and events are plain text, the workflow for managing them in the terminal is basically non-existent. Or at least, it was non-existent until khal and vdirsyncer.
|
||||
|
||||
* [Khal][14] is a console-based calendar that reads and writes `.ics` files.
|
||||
* [Vdirsyncer][14] is a terminal command that synchronizes online calendars (and contacts) to your local drive. Khal works locally and vdirsyncer works remotely, so your calendars online stay in sync with the calendar you're managing on your hard drive. ****
|
||||
* Contact management can be hard, but it gets easier if you use [Khard][15], a terminal command that reads and writes files in the vCard format. This, in turn, can be synchronized to a remote server using vdirsyncer (which you may already be using for your khal calendar). This makes calendaring and contacts easy, and it's easier than ever to [run your own personal information management (PIM) server][16].
|
||||
|
||||
|
||||
|
||||
### To-do lists
|
||||
|
||||
![][17]
|
||||
|
||||
* There are many ways to organize your day, but one of the easiest is [todo.txt][18], a simple, portable, understandable system that doesn't break down even if a device doesn't have todo.txt installed on it. The reason todo.txt works is because it's just a Bash shell script, which will run on nearly any computing device you can find. The process is simple: you download the script, install it to your home directory, and start scheduling tasks with a simple command. If you're on a computer that doesn't have the `todo.sh` command installed, your to-do list is still useful as a plain-text file, which you can update manually as needed.
|
||||
* [Jrnl][19] is a digital notebook to keep track of your daily agenda and activities. This is the program you've been looking for if you compulsively jot notes on scraps of paper on your desk or echo idle thoughts into random text files.
|
||||
|
||||
|
||||
|
||||
### Keep in touch
|
||||
|
||||
![][20]
|
||||
|
||||
Communication is key, and yet now more than ever, there seems to be a chat platform problem. There aren't just several clients, there are several isolated networks. How do you manage them all? Here are two ideas.
|
||||
|
||||
* If you've got lots of contacts spread across too many chat networks, you ought to try [BitlBee][21], the singular chat client that lets you infiltrate all the others.
|
||||
* [Rainbow Stream][22] is a Twitter client that can be awfully useful to keep you away from the distractions of an open web browser while still keeping you in touch with your adoring public.
|
||||
|
||||
|
||||
|
||||
### Keep informed
|
||||
|
||||
![][23]
|
||||
|
||||
Web browsers are nice, but they can sometimes be overkill. You want to stay informed, but you don't want to give yourself entirely over to the internet. Because the internet is built upon open specifications and a lot of open source technology, you don't have to do everything through just one interface. There are _clients_ for all kinds of tasks, and they give you access to the information you need, using the interface you prefer.
|
||||
|
||||
* [Tuir][24] is a terminal client to Reddit.
|
||||
* [Newsboat][25] is an RSS feed reader.
|
||||
* [Wego][26] brings you a weather report.
|
||||
* [Vim][27] can help you check in with Reddit and Twitter.
|
||||
* [Emacs][28] can keep you connected with clients for Reddit, Twitter, chat, and much more.
|
||||
|
||||
|
||||
|
||||
### Keep that terminal open
|
||||
|
||||
![][29]
|
||||
|
||||
If you're spending time in a terminal, what's the point in ever closing a terminal? Do away with the temptation of `exit` or `Ctrl+D` and keep your console open.
|
||||
|
||||
* [Tmux][30] lets you split your terminal, "layer" one terminal window on top of another, and even walk away from one computer and continue the same terminal session from another computer.
|
||||
* [DESQview][31] takes a different approach: it's essentially a window manager for your terminal.
|
||||
|
||||
|
||||
|
||||
### Keep going
|
||||
|
||||
The tools in this article are but a subset of amazing productivity tools for your Linux terminal. This list must end, but your personal list can grow. Find the tools you love, learn them, and use them to your greatest advantage. Of course, a good tool doesn't always have to increase your productivity: sometimes your favorite command is the one that makes you happiest. Your job is to find the commands you love and to do amazing things with them.
|
||||
|
||||
Have fun!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/productivity-tools-linux-terminal
|
||||
|
||||
作者:[Alan Smithee][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/alansmithee
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY (Computer screen with files or windows open)
|
||||
[2]: https://opensource.com/users/ksonney
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_2-1.png
|
||||
[4]: https://opensource.com/article/20/1/sync-files-syncthing
|
||||
[5]: https://opensource.com/article/20/1/configuration-management-stow
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_3-1.png
|
||||
[7]: https://opensource.com/article/20/1/sync-email-offlineimap
|
||||
[8]: https://opensource.com/article/17/11/how-use-cron-linux
|
||||
[9]: https://opensource.com/article/20/1/organize-email-notmuch
|
||||
[10]: https://opensource.com/article/20/1/vim-email-calendar
|
||||
[11]: https://opensource.com/article/20/1/emacs-mail-calendar
|
||||
[12]: https://opensource.com/sites/default/files/uploads/productivity_5-1.png
|
||||
[13]: https://tools.ietf.org/html/rfc5545
|
||||
[14]: https://opensource.com/article/20/1/open-source-calendar
|
||||
[15]: https://opensource.com/article/20/1/sync-contacts-locally
|
||||
[16]: https://opensource.com/alternatives/google-calendar
|
||||
[17]: https://opensource.com/sites/default/files/uploads/productivity_7-1.png
|
||||
[18]: https://opensource.com/article/20/1/open-source-to-do-list
|
||||
[19]: https://opensource.com/article/20/1/python-journal
|
||||
[20]: https://opensource.com/sites/default/files/uploads/productivity_9-1.png
|
||||
[21]: https://opensource.com/article/20/1/open-source-chat-tool
|
||||
[22]: https://opensource.com/article/20/1/tweet-terminal-rainbow-stream
|
||||
[23]: https://opensource.com/sites/default/files/uploads/productivity_13-1.png
|
||||
[24]: https://opensource.com/article/20/1/open-source-reddit-client
|
||||
[25]: https://opensource.com/article/20/1/open-source-rss-feed-reader
|
||||
[26]: https://opensource.com/article/20/1/open-source-weather-forecast
|
||||
[27]: https://opensource.com/article/20/1/vim-task-list-reddit-twitter
|
||||
[28]: https://opensource.com/article/20/1/emacs-social-track-todo-list
|
||||
[29]: https://opensource.com/sites/default/files/uploads/productivity_14-1.png
|
||||
[30]: https://opensource.com/article/20/1/tmux-console
|
||||
[31]: https://opensource.com/article/20/1/multiple-consoles-twin
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
311
sources/tech/20200601 How to write a VS Code extension.md
Normal file
311
sources/tech/20200601 How to write a VS Code extension.md
Normal file
@@ -0,0 +1,311 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to write a VS Code extension)
|
||||
[#]: via: (https://opensource.com/article/20/6/vs-code-extension)
|
||||
[#]: author: (Ashique Hussain Ansari https://opensource.com/users/uidoyen)
|
||||
|
||||
How to write a VS Code extension
|
||||
======
|
||||
Add missing features by writing your own extension for the popular code
|
||||
editor.
|
||||
![woman on laptop sitting at the window][1]
|
||||
|
||||
Visual Studio Code (VS Code) is a cross-platform code editor created by Microsoft for Linux, Windows, and macOS. Unfortunately, Microsoft's version of [VS Code][2] is released under the [Microsoft Software License][3], which is not an open source license. However, the source code is open source, released under the MIT license, with releases distributed by the [VSCodium][4] project.
|
||||
|
||||
VSCodium, like VS Code, has support for extensions, embedded Git control, GitHub integration, syntax highlighting, debugging, intelligent code completion, snippets, and more. In other words, for most users there's no difference between using VS Code and VSCodium, and the latter is completely open source!
|
||||
|
||||
### What are VS Code extensions?
|
||||
|
||||
Extensions allow you to add capabilities to VS Code or VSCodium. You can install extensions in the GUI or from a terminal.
|
||||
|
||||
You can also build your own extensions. There are several reasons you might want to learn to build an extension:
|
||||
|
||||
1. **To add something:** If a feature you want is missing, you can create an extension to add it.
|
||||
2. **For fun and learning:** The extension API allows you to explore how VSCodium works, which is a fun thing to do.
|
||||
3. **To improve your skills:** Creating an extension enhances your programming skills.
|
||||
4. **For fame:** Creating an extension that is useful to others can increase your public profile.
|
||||
|
||||
|
||||
|
||||
### Install the tools
|
||||
|
||||
Before you begin, you must already have [Node.js][5], [npm][6], and VS Code or [VSCodium][4] installed.
|
||||
|
||||
To generate an extension, you will also need the following tools: [Yeoman][7], an open source client-side scaffolding tool that helps you kickstart new projects, and [vscode-generator-code][8], a Yeoman generator build created by the VS Code team.
|
||||
|
||||
### Build an extension
|
||||
|
||||
In this tutorial, you will build an extension that initializes a Docker image for an application.
|
||||
|
||||
#### Generate an extension skeleton
|
||||
|
||||
To install and run the Yeoman generator globally, enter the following in a command prompt or terminal:
|
||||
|
||||
|
||||
```
|
||||
`npm install -g yo generator-code`
|
||||
```
|
||||
|
||||
Navigate to the folder where you want to generate the extension, type the following command, and hit **Enter**:
|
||||
|
||||
|
||||
```
|
||||
`yo code`
|
||||
```
|
||||
|
||||
At the prompt, you must answer some questions about your extension:
|
||||
|
||||
* **What type of extension do you want to create?** Choose one of the options by using the Up and Down arrows. In this article, I will explain only the first one, **New Extension (TypeScript)**.
|
||||
* **What's the name of your extension?** Enter the name of your extension. Mine is called **initdockerapp**. (I am sure you will have a better name.)
|
||||
* **What's the identifier of your extension?** Leave this as it is.
|
||||
* **What's the description of your extension?** Write something about your extension (you can fill this in or edit it later, too).
|
||||
* **Initialize a Git repository?** This initializes a Git repository, and you can add `set-remote` later.
|
||||
* **Which package manager to use?** You can choose yarn or npm; I will use npm.
|
||||
|
||||
|
||||
|
||||
Hit the **Enter** key, and it will start installing the required dependencies. And finally:
|
||||
|
||||
> "Your extension **initdockerapp** has been created!"
|
||||
|
||||
Excellent!
|
||||
|
||||
### Check the project's structure
|
||||
|
||||
Examine what you generated and the project structure. Navigate to the new folder and type `cd initdockerapp` in your terminal.
|
||||
|
||||
Once you are in, type `.code`. It will open in your editor and look something like this:
|
||||
|
||||
![Project file structure in VSCodium][9]
|
||||
|
||||
(Hussain Ansari, [CC BY-SA 4.0][10])
|
||||
|
||||
The two most important files to pay attention to are `package.json` and `extension.ts` inside the `src` folder.
|
||||
|
||||
#### package.json
|
||||
|
||||
First, look at `package.json`, which should look something like this:
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
"name": "initdockerapp",
|
||||
"displayName": "initdockerapp",
|
||||
"description": "",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.44.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onCommand:initdockerapp.initialize"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "initdockerapp.initialize",
|
||||
"title": "Initialize A Docker Application"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"lint": "eslint src --ext ts",
|
||||
"watch": "tsc -watch -p ./",
|
||||
"pretest": "npm run compile && npm run lint",
|
||||
"test": "node ./out/test/runTest.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.44.0",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/mocha": "^7.0.2",
|
||||
"@types/node": "^13.11.0",
|
||||
"eslint": "^6.8.0",
|
||||
"@typescript-eslint/parser": "^2.26.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||
"glob": "^7.1.6",
|
||||
"mocha": "^7.1.1",
|
||||
"typescript": "^3.8.3",
|
||||
"vscode-test": "^1.3.0"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "initdockerapp",
|
||||
"displayName": "initdockerapp",
|
||||
"description": "",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.44.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onCommand:initdockerapp.initialize"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "initdockerapp.initialize",
|
||||
"title": "Initialize A Docker Application"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"lint": "eslint src --ext ts",
|
||||
"watch": "tsc -watch -p ./",
|
||||
"pretest": "npm run compile && npm run lint",
|
||||
"test": "node ./out/test/runTest.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.44.0",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/mocha": "^7.0.2",
|
||||
"@types/node": "^13.11.0",
|
||||
"eslint": "^6.8.0",
|
||||
"@typescript-eslint/parser": "^2.26.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||
"glob": "^7.1.6",
|
||||
"mocha": "^7.1.1",
|
||||
"typescript": "^3.8.3",
|
||||
"vscode-test": "^1.3.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you are a Node.js developer, some of this might look familiar since `name`, `description`, `version`, and `scripts` are common parts of a Node.js project.
|
||||
|
||||
There are a few sections that are very important.
|
||||
|
||||
* `engines`: States which version of VSCodium the extension will support
|
||||
* `categories`: Sets the extension type; you can choose from Languages, Snippets, Linters, Themes, Debuggers, Formatters, Keymaps, and Other
|
||||
* `contributes`: A list of commands that can be used to run with your extension
|
||||
* `main`: The entry point of your extension
|
||||
* `activationEvents`: Specifies when the activation event happens. Specifically, this dictates when the extension will be loaded into your editor. Extensions are lazy-loaded, so they aren't activated until an activation event occurs
|
||||
|
||||
|
||||
|
||||
#### src/extension.ts
|
||||
|
||||
Next, look at `src/extension.ts`, which should look something like this:
|
||||
|
||||
|
||||
```
|
||||
// The module 'vscode' contains the VSCodium extensibility API
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
import * as vscode from "vscode";
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// this method is called when your extension is activated
|
||||
// your extension is activated the very first time the command is executed
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Use the console to output diagnostic information (console.log) and errors (console.error)
|
||||
// This line of code will only be executed once when your extension is activated
|
||||
console.log('Congratulations, your extension "initdockerapp" is now active!');
|
||||
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
let disposable = vscode.commands.registerCommand('initdockerapp.initialize', () => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
|
||||
let fileContent =`
|
||||
FROM node:alpine
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package.json .
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["npm", "start"]
|
||||
`;
|
||||
|
||||
fs.writeFile(path.join(vscode.workspace.rootPath, "Dockerfile"), fileContent, (err:any) => {
|
||||
if (err) {
|
||||
return vscode.window.showErrorMessage("Failed to initialize docker file!");
|
||||
}
|
||||
vscode.window.showInformationMessage("Dockerfile has been created!");
|
||||
});
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate() {}
|
||||
```
|
||||
|
||||
This is where you write the code for your extension. There's already some auto-generated code, which I'll break down.
|
||||
|
||||
Notice that the name `initdockerapp.initialize` inside `vscode.command.registerCommand` is the same as the command in `package.json`. It takes two parameters:
|
||||
|
||||
1. The name of the command to register
|
||||
2. A function to execute a command
|
||||
|
||||
|
||||
|
||||
The other function to note is `fs.writeFile`, which you wrote inside the `vscode.command.registerCommand` function. This creates a dockerfile inside your project root, and appends the code to create a Docker image.
|
||||
|
||||
### Debug the extension
|
||||
|
||||
Now that you've written the extension, its time to debug it. Click the **Run** menu and select **Start Debugging** (or just press **F5**) to open a debugging window.
|
||||
|
||||
Open the project inside the debugging window by clicking on either the **Add Folder** or the **Clone Repository** button.
|
||||
|
||||
Next, open a command panel with **Ctrl+Shift+P** (on macOS, substitute the Command key for Ctrl) and run **Initialize A Docker Application**.
|
||||
|
||||
* The first time you run this command, the activate function has not been executed since VSCodium was launched. Therefore, activate is called, and the activate function registers the command.
|
||||
* If the command has already been registered, then it executes.
|
||||
|
||||
|
||||
|
||||
You'll see a message in the lower-right corner that says: "Dockerfile has been created!" This created a Dockerfile with some pre-defined code that looks something like this:
|
||||
|
||||
![Running the new extension command][11]
|
||||
|
||||
(Hussain Ansari, [CC BY-SA 4.0][10])
|
||||
|
||||
### Summary
|
||||
|
||||
There are many helpful APIs that will help you create the extensions you want to build. The VS Code extension API has many other powerful methods you can use.
|
||||
|
||||
You can learn more about VS Code APIs in the VS Code Extension API documentation.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/vs-code-extension
|
||||
|
||||
作者:[Ashique Hussain Ansari][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/uidoyen
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-window-focus.png?itok=g0xPm2kD (young woman working on a laptop)
|
||||
[2]: https://code.visualstudio.com/
|
||||
[3]: https://code.visualstudio.com/license
|
||||
[4]: https://vscodium.com/
|
||||
[5]: https://nodejs.org/en/
|
||||
[6]: https://www.npmjs.com/
|
||||
[7]: https://yeoman.io/
|
||||
[8]: https://github.com/Microsoft/vscode-generator-code
|
||||
[9]: https://opensource.com/sites/default/files/uploads/vscode-tree.png (Project file structure in VSCodium)
|
||||
[10]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[11]: https://opensource.com/sites/default/files/uploads/vscode-run-command.png (Running the new extension command)
|
||||
@@ -0,0 +1,193 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Use FastAPI to build web services in Python)
|
||||
[#]: via: (https://fedoramagazine.org/use-fastapi-to-build-web-services-in-python/)
|
||||
[#]: author: (Clément Verna https://fedoramagazine.org/author/cverna/)
|
||||
|
||||
Use FastAPI to build web services in Python
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
_[FastAPI][2]_ is a modern Python web framework that leverage the latest Python improvement in asyncio. In this article you will see how to set up a container based development environment and implement a small web service with FastAPI.
|
||||
|
||||
### Getting Started
|
||||
|
||||
The development environment can be set up using the Fedora container image. The following Dockerfile prepares the container image with FastAPI, [Uvicorn][3] and [aiofiles][4].
|
||||
|
||||
```
|
||||
FROM fedora:32
|
||||
RUN dnf install -y python-pip \
|
||||
&& dnf clean all \
|
||||
&& pip install fastapi uvicorn aiofiles
|
||||
WORKDIR /srv
|
||||
CMD ["uvicorn", "main:app", "--reload"]
|
||||
```
|
||||
|
||||
After saving this Dockerfile in your working directory, build the container image using podman.
|
||||
|
||||
```
|
||||
$ podman build -t fastapi .
|
||||
$ podman images
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
localhost/fastapi latest 01e974cabe8b 18 seconds ago 326 MB
|
||||
```
|
||||
|
||||
Now let’s create a basic FastAPI program and run it using that container image.
|
||||
|
||||
```
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"message": "Hello Fedora Magazine!"}
|
||||
```
|
||||
|
||||
Save that source code in a _main.py_ file and then run the following command to execute it:
|
||||
|
||||
```
|
||||
$ podman run --rm -v $PWD:/srv:z -p 8000:8000 --name fastapi -d fastapi
|
||||
$ curl http://127.0.0.1:8000
|
||||
{"message":"Hello Fedora Magazine!"
|
||||
```
|
||||
|
||||
You now have a running web service using FastAPI. Any changes to _main.py_ will be automatically reloaded. For example, try changing the “Hello Fedora Magazine!” message.
|
||||
|
||||
To stop the application, run the following command.
|
||||
|
||||
```
|
||||
$ podman stop fastapi
|
||||
```
|
||||
|
||||
### Building a small web service
|
||||
|
||||
To really see the benefits of FastAPI and the performance improvement it brings ([see comparison][5] with other Python web frameworks), let’s build an application that manipulates some I/O. You can use the output of the _dnf history_ command as data for that application.
|
||||
|
||||
First, save the output of that command in a file.
|
||||
|
||||
```
|
||||
$ dnf history | tail --lines=+3 > history.txt
|
||||
```
|
||||
|
||||
The command is using _tail_ to remove the headers of _dnf history_ which are not needed by the application. Each dnf transaction can be represented with the following information:
|
||||
|
||||
* id : number of the transaction (increments every time a new transaction is run)
|
||||
* command : the dnf command run during the transaction
|
||||
* date: the date and time the transaction happened
|
||||
|
||||
|
||||
|
||||
Next, modify the _main.py_ file to add that data structure to the application.
|
||||
|
||||
```
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
class DnfTransaction(BaseModel):
|
||||
id: int
|
||||
command: str
|
||||
date: str
|
||||
```
|
||||
|
||||
FastAPI comes with the [pydantic][6] library which allow you to easily build data classes and benefit from type annotation to validate your data.
|
||||
|
||||
Now, continue building the application by adding a function that will read the data from the _history.txt_ file.
|
||||
|
||||
```
|
||||
import aiofiles
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
class DnfTransaction(BaseModel):
|
||||
id: int
|
||||
command: str
|
||||
date: str
|
||||
|
||||
|
||||
async def read_history():
|
||||
transactions = []
|
||||
async with aiofiles.open("history.txt") as f:
|
||||
async for line in f:
|
||||
transactions.append(DnfTransaction(
|
||||
id=line.split("|")[0].strip(" "),
|
||||
command=line.split("|")[1].strip(" "),
|
||||
date=line.split("|")[2].strip(" ")))
|
||||
return transactions
|
||||
```
|
||||
|
||||
This function makes use of the _[aiofiles][4]_ library which provides an asyncio API to manipulate files in Python. This means that opening and reading the file will not block other requests made to the server.
|
||||
|
||||
Finally, change the root function to return the data stored in the transactions list.
|
||||
|
||||
```
|
||||
@app.get("/")
|
||||
async def read_root():
|
||||
return await read_history()
|
||||
```
|
||||
|
||||
To see the output of the application, run the following command
|
||||
|
||||
```
|
||||
$ curl http://127.0.0.1:8000 | python -m json.tool
|
||||
[
|
||||
{
|
||||
"id": 103,
|
||||
"command": "update",
|
||||
"date": "2020-05-25 08:35"
|
||||
},
|
||||
{
|
||||
"id": 102,
|
||||
"command": "update",
|
||||
"date": "2020-05-23 15:46"
|
||||
},
|
||||
{
|
||||
"id": 101,
|
||||
"command": "update",
|
||||
"date": "2020-05-22 11:32"
|
||||
},
|
||||
....
|
||||
]
|
||||
```
|
||||
|
||||
### Conclusion
|
||||
|
||||
_FastAPI_ is gaining a lot a popularity in the Python web framework ecosystem because it offers a simple way to build web services using asyncio. You can find more information about _FastAPI_ in the [documentation][2].
|
||||
|
||||
The code of this article is available in [this GitHub repository][7].
|
||||
|
||||
* * *
|
||||
|
||||
_Photo by [Jan Kubita][8] on [Unsplash][9]._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/use-fastapi-to-build-web-services-in-python/
|
||||
|
||||
作者:[Clément Verna][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/cverna/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/05/fastapi-python-816x345.jpg
|
||||
[2]: https://fastapi.tiangolo.com/
|
||||
[3]: https://www.uvicorn.org/
|
||||
[4]: https://github.com/Tinche/aiofiles
|
||||
[5]: https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=composite&l=z8kflr-v&a=2&f=jz8cg-0-3s-0-3k-6bo-0-0-18y74-8s5c-0
|
||||
[6]: https://pydantic-docs.helpmanual.io/
|
||||
[7]: https://github.com/cverna/fastapi_app
|
||||
[8]: https://unsplash.com/@jankubita?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[9]: https://unsplash.com/s/photos/fast-snake?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
@@ -0,0 +1,258 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (When to choose C or Python for a command-line interface)
|
||||
[#]: via: (https://opensource.com/article/20/6/c-python-cli)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
When to choose C or Python for a command-line interface
|
||||
======
|
||||
Take lessons from the history of C and learn how to write useful CLI
|
||||
programs in Python.
|
||||
![Searching for code][1]
|
||||
|
||||
This article has a simple goal: to help new Python developers with some of the history and terminology around [command-line interfaces][2] (CLIs) and explore how to write these useful programs in Python.
|
||||
|
||||
### In the beginning…
|
||||
|
||||
First, a [Unix][3] perspective on command-line interface design.
|
||||
|
||||
Unix is a computer operating system and the ancestor of Linux and macOS (and many other operating systems as well). Before graphical user interfaces, the user interacted with the computer via a command-line prompt (think of today's [Bash][4] environment). The primary language for developing these programs under Unix is [C][5], which is amazingly [powerful][6].
|
||||
|
||||
So it behooves us to at least understand the basics of a [C program][7].
|
||||
|
||||
Assuming you didn't read that link, the basic architecture of a C program is a function called `main`, and its signature looks like this:
|
||||
|
||||
|
||||
```
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
This shouldn't look too strange to a Python programmer. C functions have a return type first, a function name, and then the typed arguments inside the parenthesis. Last, the body of the function resides between the curly braces. The function name `main` is how the [runtime linker][8] (the program that constructs and runs programs) decides where to start executing your program. If you write a C program and it doesn't include a function named `main`, it will not do anything. Sad.
|
||||
|
||||
The function argument variables `argc` and `argv` together describe a list of strings that are typed by the user on the command line when the program is invoked. In the typical terse Unix naming tradition, `argc` means _argument count_ and `argv` means _argument vector_. Vector sounds cooler than list, and `argl` sounds like a strangled cry for help. We are Unix system programmers, and we do not cry for help. We make _other_ people cry for help.
|
||||
|
||||
#### Moving on
|
||||
|
||||
|
||||
```
|
||||
`$ ./myprog foo bar -x baz`
|
||||
```
|
||||
|
||||
If `myprog` is implemented in C, `argc` will have the value 5 and `argv` will be an array of pointers to characters with five entries. (Don't worry if that sounds super-technical; it's a list of five strings.) The first entry in the vector, `argv[0]`, is the name of the program. The rest of `argv` contains the arguments:
|
||||
|
||||
|
||||
```
|
||||
argv[0] == "./myprog"
|
||||
argv[1] == "foo"
|
||||
argv[2] == "bar"
|
||||
argv[3] == "-x"
|
||||
argv[4] == "baz"
|
||||
|
||||
/* Note: not valid C */
|
||||
```
|
||||
|
||||
In C, you have many choices to handle the strings in `argv`. You could loop over the array `argv` _manually_ and interpret each of the strings according to the needs of the program. This is relatively easy, but it leads to programs with wildly different interfaces, as different programmers have different ideas about what is "good."
|
||||
|
||||
|
||||
```
|
||||
include <stdio.h>
|
||||
|
||||
/* A simple C program that prints the contents of argv */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
|
||||
for(i=0; i<argc; i++)
|
||||
[printf][9]("%s\n", argv[i]);
|
||||
}
|
||||
```
|
||||
|
||||
#### Early attempts to standardize the command line
|
||||
|
||||
The next weapon in the command-line arsenal is a [C standard library][10] function called [`getopt`][11]. This function allows the programmer to parse switches, arguments with a dash preceding it, like `-x`, and optionally pair follow-on arguments with their switches. Think about command invocations like "`/bin/ls -alSh", ``getopt` is the function originally used to parse that argument string. Using `getopt` makes parsing the command line pretty easy and improves the user experience (UX).
|
||||
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#define OPTSTR "b:f:"
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int opt;
|
||||
char *bar = NULL;
|
||||
char *foo = NULL;
|
||||
|
||||
while((opt=getopt(argc, argv, OPTSTR)) != EOF)
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
bar = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
foo = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
default':
|
||||
fprintf(stderr, "Huh? try again.");
|
||||
exit(-1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
printf("%s\n", foo ? foo : "Empty foo");
|
||||
printf("%s\n", bar ? bar : "Empty bar");
|
||||
}
|
||||
```
|
||||
|
||||
On a personal note, I _wish_ Python had `switch`es, but that will [never][12], ever [happen][13].
|
||||
|
||||
#### The GNU generation
|
||||
|
||||
The [GNU][14] project came along and introduced longer format arguments for their implementations of traditional Unix command-line tools, things like `--file-format foo`. Of course, we Unix programmers hated that because it was too much to type, but like the dinosaurs we are, we lost because the users _liked_ the longer options. I never wrote any code using the GNU-style option parsing, so no code example here.
|
||||
|
||||
GNU-style arguments also accept short names like `-f foo` that have to be supported, too. All of this choice resulted in more workload for the programmer who just wanted to know what the user was asking for and get on with it. But the user got an even more consistent UX: long and short format options and automatically generated help that often kept the user from attempting to read infamously difficult-to-parse [manual][15] pages (see [`ps`][16] for a particularly egregious example).
|
||||
|
||||
### But we're talking about Python?
|
||||
|
||||
You have now been exposed to enough (too much?) command-line history to have some context about how to approach writing CLIs with our favorite language. Python gives a similar number of choices for command-line parsing; do it yourself, a batteries-included option, and a plethora of third-party options. Which one you choose depends on your particular circumstances and needs.
|
||||
|
||||
#### First, do it yourself
|
||||
|
||||
You can get your program's arguments from the [`sys`][17] module.
|
||||
|
||||
|
||||
```
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
for value in sys.argv:
|
||||
print(value)
|
||||
```
|
||||
|
||||
#### Batteries included
|
||||
|
||||
There have been several implementations of argument-parsing modules in the Python standard library; [`getopt`][18], [`optparse`][19], and most recently, [`argparse`][20]. `Argparse` allows the programmer to provide the user with a consistent and helpful UX, but like its GNU antecedents, it takes a lot of work and "[boilerplate code][21]" on the part of the programmer to make it "good."
|
||||
|
||||
|
||||
```
|
||||
from argparse import ArgumentParser
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
argparser = ArgumentParser(description='My Cool Program')
|
||||
argparser.add_argument("--foo", "-f", help="A user supplied foo")
|
||||
argparser.add_argument("--bar", "-b", help="A user supplied bar")
|
||||
|
||||
results = argparser.parse_args()
|
||||
print(results.foo, results.bar)
|
||||
```
|
||||
|
||||
The payoff is automatically generated help available when the user invokes `--help`. But what about the advantage of [batteries included][22]? Sometimes the circumstances of your project dictate that you have limited or no access to third-party libraries, and you have to "make do" with the Python standard library.
|
||||
|
||||
#### A modern approach to CLIs
|
||||
|
||||
And then there was [`Click`][23]. The `Click` framework uses a [decorator][24] approach to building command-line parsing. All of a sudden, it's fun and easy to write a rich command-line interface. Much of the complexity melts away under the cool and futuristic use of decorators, and users marvel at the automatic support for keyword completion as well as contextual help. All while writing less code than previous solutions. Anytime you can write less code and still get things done is a win. And we all want wins.
|
||||
|
||||
|
||||
```
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.option("-f", "--foo", default="foo", help="User supplied foo.")
|
||||
@click.option("-b", "--bar", default="bar", help="User supplied bar.")
|
||||
def echo(foo, bar):
|
||||
"""My Cool Program
|
||||
|
||||
It does stuff. Here is the documentation for it.
|
||||
"""
|
||||
print(foo, bar)
|
||||
|
||||
if __name__ == "__main__":
|
||||
echo()
|
||||
```
|
||||
|
||||
You can see some of the same boilerplate code in the `@click.option` decorator as you saw with `argparse`. But the "work" of creating and managing the argument parser has been abstracted away. Now the function `echo` is called _magically_ with the command-line arguments parsed and the values assigned to the function arguments.
|
||||
|
||||
Adding arguments to a `Click` interface is as easy as adding another decorator to the stack and adding the new argument to the function definition.
|
||||
|
||||
### But wait, there's more!
|
||||
|
||||
Built on top of `Click`, [`Typer`][25] is an even _newer_ CLI framework that combines the functionality of Click with modern Python [type hinting][26]. One of the drawbacks of using Click is the stack of decorators that have to be added to a function. CLI arguments have to be specified in two places: the decorator and the function argument list. `Typer` [DRYs][27] out CLI specifications, resulting in code that's easier to read and maintain.
|
||||
|
||||
|
||||
```
|
||||
import typer
|
||||
|
||||
cli = typer.Typer()
|
||||
|
||||
@cli.command()
|
||||
def echo(foo: str = "foo", bar: str = "bar"):
|
||||
"""My Cool Program
|
||||
|
||||
It does stuff. Here is the documentation for it.
|
||||
"""
|
||||
print(foo, bar)
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
```
|
||||
|
||||
### Time to start writing some code
|
||||
|
||||
Which one of these approaches is right? It depends on _your_ use case. Are you writing a quick and dirty script that only you will use? Use `sys.argv` directly and drive on. Do you need more robust command-line parsing? Maybe `argparse` is enough. Do you have lots of subcommands and complicated options, and is your team going to use it daily? Now you should definitely consider `Click` or `Typer`. Part of the fun of being a programmer is hacking out alternate implementations to see which one suits you best.
|
||||
|
||||
Finally, there are _many_ third-party packages for parsing command-line arguments in Python. I've only presented the ones I like or have used. It is entirely fine and expected for you to like and/or use different packages. My advice is to start with these and see where you end up.
|
||||
|
||||
Go write something cool.
|
||||
|
||||
* * *
|
||||
|
||||
_This article originally appeared on [PyBites][28] and is republished with permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/c-python-cli
|
||||
|
||||
作者:[Erik O'Shaughnessy][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/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/search_find_code_python_programming.png?itok=ynSL8XRV (Searching for code)
|
||||
[2]: https://en.wikipedia.org/wiki/Command-line_interface
|
||||
[3]: https://en.wikipedia.org/wiki/Unix
|
||||
[4]: https://www.gnu.org/software/bash/
|
||||
[5]: https://en.wikipedia.org/wiki/C_(programming_language)
|
||||
[6]: https://www.toptal.com/c/after-all-these-years-the-world-is-still-powered-by-c-programming
|
||||
[7]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[8]: https://en.wikipedia.org/wiki/Dynamic_linker
|
||||
[9]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
|
||||
[10]: https://en.wikipedia.org/wiki/C_standard_library
|
||||
[11]: http://man7.org/linux/man-pages/man3/getopt.3.html
|
||||
[12]: https://www.python.org/dev/peps/pep-0275/
|
||||
[13]: https://www.python.org/dev/peps/pep-3103/
|
||||
[14]: https://www.gnu.org
|
||||
[15]: https://en.wikipedia.org/wiki/Man_page
|
||||
[16]: http://man7.org/linux/man-pages/man1/ps.1.html
|
||||
[17]: https://docs.python.org/3/library/sys.html
|
||||
[18]: https://docs.python.org/2/library/getopt.html
|
||||
[19]: https://docs.python.org/2/library/optparse.html
|
||||
[20]: https://docs.python.org/3/library/argparse.html
|
||||
[21]: https://en.wikipedia.org/wiki/Boilerplate_code
|
||||
[22]: https://www.python.org/dev/peps/pep-0206/
|
||||
[23]: https://click.palletsprojects.com/en/7.x/
|
||||
[24]: https://wiki.python.org/moin/PythonDecorators
|
||||
[25]: https://typer.tiangolo.com
|
||||
[26]: https://docs.python.org/3/library/typing.html
|
||||
[27]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
|
||||
[28]: https://pybit.es/guest-exploring-python-clis.html
|
||||
@@ -0,0 +1,174 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Using the Lightweight Apt Package Manager Synaptic in Ubuntu and Other Debian-based Linux Distributions)
|
||||
[#]: via: (https://itsfoss.com/synaptic-package-manager/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
Using the Lightweight Apt Package Manager Synaptic in Ubuntu and Other Debian-based Linux Distributions
|
||||
======
|
||||
|
||||
This week’s open source software highlight is Synaptic. Learn what this good old package manager can do that the modern software managers cannot.
|
||||
|
||||
### What is Synaptic package manager?
|
||||
|
||||
[Synaptic][1] is a lightweight GUI front end to [apt package management system][2] used in Debian, Ubuntu, Linux Mint and many other Debian/Ubuntu based distributions.
|
||||
|
||||
Basically, everything that you can do [using the apt-get commands in the terminal][3] can be achieved with Synaptic.
|
||||
|
||||
![][4]
|
||||
|
||||
There was a time when Synaptic was the default graphical software manager on almost all Debian-based Linux distributions. It was considered to be a user-friendly, easy to use way of managing applications.
|
||||
|
||||
Things changed as modern software manager tools like [GNOME Software][5] and [KDE Discover][6] came up with more modern and intuitive UI. These software managers have better interface, display the package information in a more friendly way with thumbnails, ratings and reviews.
|
||||
|
||||
Eventually, Synaptic got [confined to mostly lightweight Linux distributions][7].
|
||||
|
||||
#### Why would you use an ‘ancient’ software like Synaptic package manager?
|
||||
|
||||
You don’t have to. Not most of the time, of course.
|
||||
|
||||
But Synaptic is still a lot versatile than the likes of GNOME Software. Remember, it is basically GUI front end to apt which means it can do (almost) everything you do with [apt commands in the terminal][8].
|
||||
|
||||
For example, if you want to [prevent the update of a specific package in Ubuntu][9], you can do that in Synaptic but not in GNOME/Ubuntu Software Center.
|
||||
|
||||
![][10]
|
||||
|
||||
Also, I have noticed some issues with the Software Center in Ubuntu 20.04. It’s slow to load, it’s slow when searching for software and it is full of snap application (that not everyone prefers).
|
||||
|
||||
Synaptic is also [one of the lightweight applications you can use in Ubuntu][7] to speed up your system a bit.
|
||||
|
||||
#### Synaptic package manager features
|
||||
|
||||
Here is a summary of what you can do with Synaptic:
|
||||
|
||||
* Update the package cache
|
||||
* Upgrade the entire system
|
||||
* Manage package repositories
|
||||
* Search for packages by name, description, maintainer, version, dependencies etc
|
||||
* List packages by section, status (installed), origin or more
|
||||
* Sort packages by name, status, size or version
|
||||
* Get information related to a package
|
||||
* Lock package version
|
||||
* Install specific version of a package
|
||||
|
||||
|
||||
|
||||
There are more features that you may explore on your own.
|
||||
|
||||
### How to install Synaptic package manager on Ubuntu
|
||||
|
||||
Synaptic package manager is available in the Universe repository in Ubuntu. If it is enabled, you may find it in the Software Center:
|
||||
|
||||
![Synaptic in Ubuntu Software Center][11]
|
||||
|
||||
You may also install Synaptic via command line. Make sure to enable universe repository first:
|
||||
|
||||
```
|
||||
sudo add-apt-repository univers
|
||||
```
|
||||
|
||||
And then update the cache (not required in Ubuntu 18.04 and higher versions):
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
Now, use the command below to install synaptic package manager:
|
||||
|
||||
```
|
||||
sudo apt install synaptic
|
||||
```
|
||||
|
||||
That’s it.
|
||||
|
||||
### How to use Synaptic package manager
|
||||
|
||||
Once installed, you can search for Synaptic in the menu and start it from there:
|
||||
|
||||
![][12]
|
||||
|
||||
You can see that the interface is not among the best-looking ones here. Note the color of the checkboxes. White means the package is not installed, green means it is installed.
|
||||
|
||||
![][4]
|
||||
|
||||
You can search for an application and click on the checkbox to mark it for installation. It will also highlight packages (in green) that will be installed as dependencies. Hit apply to install the selected packages:
|
||||
|
||||
![][13]
|
||||
|
||||
You can [see all the installed packages in Ubuntu][14] using Synaptic. You can also choose to remove packages from this view.
|
||||
|
||||
![][15]
|
||||
|
||||
You can see packages available in individual repositories by displaying them based on Origin. Good way to see [which PPA offers what packages][16]. You can install or remove packages as described above.
|
||||
|
||||
![][17]
|
||||
|
||||
Usually, when you update Ubuntu, all the packages are updated at once. With Synaptic, you can easily choose which packages you want to update/upgrade to a newer version.
|
||||
|
||||
![][18]
|
||||
|
||||
You can also lock the version of packages so that they don’t get updated along with the system updates.
|
||||
|
||||
![][10]
|
||||
|
||||
You can also search for packages using Synaptic. This is like [searching for packages using apt-cache search command][19].
|
||||
|
||||
![][20]
|
||||
|
||||
If you think you made the wrong selection, you can click Undo from the Edit menu.
|
||||
|
||||
There are plenty more you can do with Synaptic and I cannot cover all the possible usages. I have covered the most common ones here and I leave you to explore it, if you are going to use Synaptic.
|
||||
|
||||
### Synaptic is not for everyone
|
||||
|
||||
If you don’t like Synaptic, you can remove it from the Software Center or using this command in terminal:
|
||||
|
||||
```
|
||||
sudo apt remove synaptic
|
||||
```
|
||||
|
||||
There was another lightweight software manager for Ubuntu called [AppGrid][21]. It hasn’t been updated in recent times as far as I know.
|
||||
|
||||
Synaptic is certainly not for everyone. It lists libraries and packages that you won’t otherwise see in the regular Software Center. If you removed a library that you were not aware of, it may cause issues.
|
||||
|
||||
I think that Synaptic is suitable for intermediate to advanced users who want better control over the package management without going the command line way.
|
||||
|
||||
What do you say? Have you ever used Synaptic for package management? Do you reply on software center or you just dive into the terminal? Do share your preference in the comment section.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/synaptic-package-manager/
|
||||
|
||||
作者:[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://www.nongnu.org/synaptic/
|
||||
[2]: https://en.wikipedia.org/wiki/APT_(software)
|
||||
[3]: https://itsfoss.com/apt-get-linux-guide/
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/06/synaptic-interface.png?ssl=1
|
||||
[5]: https://wiki.gnome.org/Apps/Software
|
||||
[6]: https://userbase.kde.org/Discover
|
||||
[7]: https://itsfoss.com/lightweight-alternative-applications-ubuntu/
|
||||
[8]: https://itsfoss.com/apt-command-guide/
|
||||
[9]: https://itsfoss.com/prevent-package-update-ubuntu/
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/lock-version-synaptic.png?ssl=1
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/06/synaptic-ubuntu-software-center.png?ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/06/synaptic-package-manager-ubuntu.jpg?ssl=1
|
||||
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/install-packages-in-synaptic.png?ssl=1
|
||||
[14]: https://itsfoss.com/list-installed-packages-ubuntu/
|
||||
[15]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/06/remove-packages-using-synaptic.png?ssl=1
|
||||
[16]: https://itsfoss.com/ppa-guide/
|
||||
[17]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/see-packages-by-repositories-synaptic.png?ssl=1
|
||||
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/06/upgrade-packages-synaptic.png?ssl=1
|
||||
[19]: https://itsfoss.com/apt-search-command/
|
||||
[20]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/06/search-results-synaptic.png?ssl=1
|
||||
[21]: https://itsfoss.com/app-grid-lighter-alternative-ubuntu-software-center/
|
||||
@@ -0,0 +1,198 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to Remove Files Older than N Days Using Tmpwatch/Tmpreaper on Linux)
|
||||
[#]: via: (https://www.2daygeek.com/how-to-remove-files-older-than-n-days-using-tmpwatch-tmpreaper-on-linux/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
如何在 Linux 上使用 Tmpwatch/Tmpreaper 删除早于 N 天的文件
|
||||
======
|
||||
|
||||
你可能错过了删除计算机上某个目录中不再需要的文件的操作。
|
||||
|
||||
这可以是“下载”或任何其他目录。
|
||||
|
||||
它可能已经增长了一段时间。
|
||||
|
||||
如果有足够的存储空间,那么你应删除它们,因为这会在列出文件时降低系统速度。
|
||||
|
||||
同样,当一个目录中有成千上万个文件时,它可能很会很臃肿。
|
||||
|
||||
当你不知道要检查的文件名时,很难在特定目录中找到文件。
|
||||
|
||||
我们可以通过结合使用 find 命令和一些组合来做到这一点,我们过去已经写过一篇文章。
|
||||
|
||||
* [**使用 Bash 脚本在 Linux 中删除早于 “X” 天的文件/文件夹**][1]
|
||||
* [**如何在 Linux 中查找和删除早于 “X” 天和 “X” 小时的文件**][1]
|
||||
* [**如何在 Linux 中自动删除或清理 /tmp 文件夹内容?**][1]
|
||||
|
||||
|
||||
|
||||
今天,我们将向你展示如何在 Linux 上使用 Tmpwatch 程序来实现这一目标。
|
||||
|
||||
### 什么是 Tmpwatch
|
||||
|
||||
Tmpwatch 递归删除指定时间段内未在指定目录中被访问的文件。
|
||||
|
||||
通常,它用于自动清除临时文件系统目录,例如 /tmp 和 /var/tmp。
|
||||
|
||||
它仅删除空目录、常规文件和符号链接。
|
||||
|
||||
它不会切换到其他文件系统,并避免了属于根用户的 “lost+found” 目录。
|
||||
|
||||
默认情况下,tmpwatch 会根据文件的 atime (访问时间)而不是 mtime (修改时间)删除文件。
|
||||
|
||||
你可以在 tmpwatch 命令中添加其他参数来更改此行为。
|
||||
|
||||
**警告:** 请不要在 “/” 中运行 “tmpwatch” 或 “tmpreaper”,因为程序中没有防止这种情况的机制。
|
||||
|
||||
### 如何在 Linux 上安装 Tmpwatch
|
||||
|
||||
可以在官方仓库中按以下方式安装 Tmpwatch。
|
||||
|
||||
对于 **RHEL/CentOS 6** 系统,请使用 **[yum 命令][2]**安装 Tmpwatch。
|
||||
|
||||
```
|
||||
$ sudo yum install -y tmpwatch
|
||||
```
|
||||
|
||||
对于 **Debian** 和 **Ubuntu** 系统,请使用 **[apt 命令][3]** 或 **[apt-get 命令][4]** 安装 Tmpreaper。
|
||||
|
||||
```
|
||||
$ sudo apt-get install tmpreaper
|
||||
```
|
||||
|
||||
对于 **openSUSE** 系统,请使用 **[zypper 命令][5]** 安装 Tmpwatch。
|
||||
|
||||
```
|
||||
$ sudo zypper install -y tmpwatch
|
||||
```
|
||||
|
||||
对于 **Fedora** 系统,请使用 **[dnf 命令][6]** 安装 Tmpwatch。
|
||||
|
||||
```
|
||||
$ sudo dnf install -y tmpwatch
|
||||
```
|
||||
|
||||
**请注意:** 如果你使用的是基于 Debian 的系统,请使用 “tmpreaper” 而不是 tmpwatch。所有例子都将按预期工作。
|
||||
|
||||
### 了解关键选项和参数
|
||||
|
||||
* **atime**(文件上次访问时间)– atime 显示命令或脚本等任意进程最后一次访问文件中数据的时间。
|
||||
* **mtime**(文件上次修改时间)– mtime 显示你修改文件内容或保存文件的时间。除非文件属性被更新,否则大多数情况下 ctime 和 mtime 会相同。
|
||||
* **ctime**(文件上次更改时间)– ctime 显示文件元数据更改时间。这意味着更改文件属性的时间(如所有权或组等)。
|
||||
* **dirmtime**(目录的上次修改时间)– dirmtime 显示目录的上一次修改时间。
|
||||
|
||||
|
||||
|
||||
time 参数定义删除文件的阈值。
|
||||
|
||||
* d – 天
|
||||
* h – 小时
|
||||
* m – 分钟
|
||||
* s – 秒
|
||||
|
||||
|
||||
|
||||
### 如何使用 Tmpwatch 命令删除一段时间未访问的文件
|
||||
|
||||
正如我在本文开头所说,Tmpwatch 默认(atime)根据文件访问时间删除文件。另外,由于小时是默认参数,因此如果使用小时单位,那么无需在时间上添加后缀。
|
||||
|
||||
例如,运行以下命令以递归方式删除过去 5 个小时未访问的文件。
|
||||
|
||||
```
|
||||
# tmpwatch 5 /tmp
|
||||
```
|
||||
|
||||
运行以下命令删除最近 10 个小时未修改的文件。如果要使用 mtime 删除文件,那么需要在 tmpwatch 命令中添加 “-m” 选项。
|
||||
|
||||
```
|
||||
# tmpwatch -m 10 /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### 如何使用 Tmpwatch 命令删除超过 “X” 天未访问的文件
|
||||
|
||||
如果要使用天数删除文件,那么需要添加后缀 “d”。以下示例删除了 30 天以上的文件。
|
||||
|
||||
```
|
||||
# tmpwatch 30d /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### 如何使用 Tmpwatch 命令删除一段时间内未访问的所有文件
|
||||
|
||||
以下命令将删除所有文件类型,而不仅仅是基于 mtime 的常规文件、符号链接和目录。
|
||||
|
||||
```
|
||||
# tmpwatch -am 12 /tmp
|
||||
```
|
||||
|
||||
### 如何在 Tmpwatch 中排除目录
|
||||
|
||||
以下命令将删除所有文件,并排除过去 10 个小时未修改的目录。
|
||||
|
||||
```
|
||||
# tmpwatch -am 10 --nodirs /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### 如何在 Tmpwatch 中排除特定路径
|
||||
|
||||
以下命令将删除所有文件,除了下面在过去 10 个小时未被修改的文件夹。
|
||||
|
||||
```
|
||||
# tmpwatch -am 10 --exclude=/home/daygeek/Downloads/Movies /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### 如何在 Tmpwatch 中排除特定模式
|
||||
|
||||
以下命令将删除所有文件,除了下面在过去 10 小时未被修改的满足该模式的文件。
|
||||
|
||||
```
|
||||
# tmpwatch -am 10 --exclude-pattern='*.pdf' /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### 如何让 Tmpwatch 命令空运行
|
||||
|
||||
如果要空运行,请运行以下命令。
|
||||
|
||||
```
|
||||
# tmpwatch -t 5h /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
### 如何设置 cronjob 来使用 Tmpwatch 定期删除文件
|
||||
|
||||
默认情况下,它在 **“/etc/cron.daily/tmpreaper”** 目录下有一个 **[cronjob][7]** 文件。该 cronjob 根据位于 **“/etc/timereaper.conf”** 中的配置文件工作。你可以根据需要自定义文件。
|
||||
|
||||
它每天运行一次,并删除 7 天之前的文件。
|
||||
|
||||
另外,如果你希望常规执行某项操作,那么可以根据需要手动添加一个 cronjob。
|
||||
|
||||
```
|
||||
# crontab -e
|
||||
|
||||
0 10 * * * /usr/sbin/tmpwatch 15d /home/daygeek/Downloads
|
||||
```
|
||||
|
||||
上面的 cronjob 将在每天上午 10 点删除早于 15 天的文件。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/how-to-remove-files-older-than-n-days-using-tmpwatch-tmpreaper-on-linux/
|
||||
|
||||
作者:[Magesh Maruthamuthu][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://www.2daygeek.com/author/magesh/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.2daygeek.com/bash-script-to-delete-files-folders-older-than-x-days-in-linux/
|
||||
[2]: https://www.2daygeek.com/linux-yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[3]: https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[4]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[5]: https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[6]: https://www.2daygeek.com/linux-dnf-command-examples-manage-packages-fedora-centos-rhel-systems/
|
||||
[7]: https://www.2daygeek.com/linux-crontab-cron-job-to-schedule-jobs-task/
|
||||
@@ -0,0 +1,149 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (20 productivity tools for the Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/20/6/productivity-tools-linux-terminal)
|
||||
[#]: author: (Alan Smithee https://opensource.com/users/alansmithee)
|
||||
|
||||
20 个 Linux 终端下的生产力工具
|
||||
======
|
||||
来试下这些开源工具。你的效率一定会提升。
|
||||
![Computer screen with files or windows open][1]
|
||||
|
||||
诚然,很多人使用计算机来娱乐。但是一些人会用来工作,他们的理论是计算机应当能帮我们更快、更好、更有组织地做事。实际应用中,如果没有根据每个人的工作风格来做一些小小的手动配置,计算机也不会提升我们的效率。
|
||||
|
||||
[Kevin Sonney][2] 喜欢设计系统,今年他在一个 20 篇文章的系列中介绍了 18 种不同的生产力工具,不仅涵盖了网络方面,也涉及了一些能提升他的工作效率的工具。Kevin 最喜欢的所有的工具都收集到了本文,下面概括介绍每种工具的用途。
|
||||
|
||||
### 文件同步
|
||||
|
||||
![][3]
|
||||
|
||||
重要的文件应谨慎管理。
|
||||
|
||||
* [Syncthing][4] 能使不同设备上的文件彼此同步。*设备*可以是 Linux、Windows 或 Mac、一台服务器、Android 平板或手机,等等。文件可以是你期望在多台机器间同步的任意文件。Syncthing 是轻量级的点对点工具,因此你不需要花费时间搭建服务,你不需要第三方的服务器,而且它很快。
|
||||
* 同步是一件事,但有时你还需要帮忙处理文件。假设你有一个应用程序,它在被作为一个图形化应用和作为控制台应用时有不同的展现形式。你可以它的符号链接指向的修改配置文件,如 `.foo-gui` 和 `.foo-term`。这完全可以手动修改,但也可以用脚本处理,或者你可以试试 [GNU Stow][5]。
|
||||
|
||||
|
||||
|
||||
### 邮件管理
|
||||
|
||||
![][6]
|
||||
|
||||
我们都依赖邮件和收件箱,但我们几乎没有人对管理邮件的方式很满意。如果你喜欢用终端工作,为什么不在终端里管理邮件呢?在终端里收发邮件是一件事,但是在终端里组织你的邮件会令人兴奋。如果你的职业是打字员或是天生的编剧,试试这类工具吧。
|
||||
|
||||
* 我每天用 [OfflineIMAP][7] 把工作邮件同步到笔记本,用 Mutt 看邮件。它是很特别的工具,只做一件事:保证本地的邮件副本与远程的收件箱完全同步。配置和用 [cron][8] 调度它都相当简单,然后你就可以忘了它的存在。它相当简单,你与 IMAP 打交道的时间都应该用它。
|
||||
* [Notmuch][9] 能为邮件消息简历索引、加标签以及搜索邮件。如果你的收件箱出了问题,*不需要*花费很大精力去补救。
|
||||
* [Vim][10] 可以收发邮件和管理你的日历。
|
||||
* 当然,[Emacs][11] 可以收发邮件和管理你的日历。
|
||||
|
||||
|
||||
|
||||
### 日历和联系人
|
||||
|
||||
![][12]
|
||||
|
||||
我用过的所有的 Linux 系统都预装了 `cal` 命令。这是一个在终端下用的便捷小日历,它也是个伟大的速查工具。然而,它几乎不能被称为一个日历应用程序。[iCalendar][13] 说明书(不是 Apple 的旧桌面日历)中提供了丰富的共享日历功能,`.ics` 约定了事件是纯文本,这导致了在终端中管理它们的工作流不会存在。至少,在 khal 和 vdirsyncer 出现之前不存在。
|
||||
|
||||
* [Khal][14] 是基于控制台的读写 `.ics` 文件的日历工具。
|
||||
* [Vdirsyncer][14] 是一个能把线上日历(和联系人)同步到本地的终端命令。Khal 在本地运行,vdirsyncer 在远程运行,这样远程的日历能与你管理的本地日历保持同步。
|
||||
* 管理联系人可能会很难,但是如果你用了 [Khard][15] 这个以 vCard 格式读写文件的终端命令,就会变得简单。这个命令能反过来同步运行着 vdirsyncer(你可能在用 khal 日历时已经运行了)的远程服务器。这使得日历和联系人管理变得简单,而且[搭建个人信息管理(PIM)服务器][16]也比以前容易得多。
|
||||
|
||||
|
||||
|
||||
### 待办清单
|
||||
|
||||
![][17]
|
||||
|
||||
* 组织你每天的行程有很多种方式,但是最简单的一种是用 [todo.txt][18],一个简单、便携式、易于理解的系统,即使设备上没有安装 todo.txt 也不会崩溃。todo.txt 能正常运行的原因是,它就是一个 Bash 脚本,能在几乎所有你能找到的的设备上运行。操作过程很简单:下载脚本,安装到家目录,用一个简单的命令开始调度任务。如果你的计算机上没有安装 `todo.sh` 命令,那么你的待办清单仍然可以作为纯文本文件来使用,你可以在需要时手动更新它。
|
||||
* [Jrnl][19] 是一个能追踪的你的日常议程和活动的数字笔记本。如果你要摘抄桌面上的报纸的片段或者把随意的想法写下来,那么这就是你要找的程序。
|
||||
|
||||
|
||||
|
||||
### 保持联络
|
||||
|
||||
![][20]
|
||||
|
||||
现在交流比以前更关键,但是管理交流平台是个问题。这不仅仅是几个客户端,而是几个独立的网络。你怎么管理它们?这里有两个方案。
|
||||
|
||||
* 如果你在很多个交流网络中积累了大量的联系人,那么你应该试试 [BitlBee][21],使用这一个聊天客户端就可以关联其他所有的客户端。
|
||||
* [Rainbow Stream][22] 是个推特客户端,能让你不被开放的网页浏览器分心,而又能紧跟时事。
|
||||
|
||||
|
||||
|
||||
### 消息通知
|
||||
|
||||
![][23]
|
||||
|
||||
网页浏览器很好,但有时过犹不及。你希望能及时收到消息,但是你又不想全身心地投入到互联网中。因为互联网是以开放的规格和大量的开源技术构建的,你不必在一个界面中做所有的事。对于不同的任务有不同的*客户端*,通过它们你能得到需要的信息,你只需要使用喜欢的界面就可以了。
|
||||
|
||||
* [Tuir][24] 是一个 Reddit 终端客户端。
|
||||
* [Newsboat][25] 是一个 RSS 阅读器。
|
||||
* [Wego][26] 是天气预报工具。
|
||||
* [Vim][27] 可以帮助你登录 Reddit 和 Twitter。
|
||||
* [Emacs][28] 能让你保持与 Reddit、Twitter 和聊天客户端的联系。
|
||||
|
||||
|
||||
|
||||
### 保持终端一直开启
|
||||
|
||||
![][29]
|
||||
|
||||
如果你正在用终端工作,那么关闭它的意义是什么呢?屏蔽掉 `exit` 和 `Ctrl+D`,保持你的控制台一直开启。
|
||||
|
||||
* [Tmux][30] 能分割你的终端,让一个终端窗口”分层“到另一个窗口之上,甚至从一台计算机离开到另一台计算机后,能保持相同的终端会话。
|
||||
* [DESQview][31] 是另一种方式:它本质上是一个终端窗口管理器。
|
||||
|
||||
|
||||
|
||||
### 未完待续
|
||||
|
||||
本文列出的工具只是 Linux 终端的神奇生产力工具中的一小部分。这个清单会结束,但你自己的清单可以继续列。找到你喜欢的工具,学习它们,让他们为你带来最大的收益。当然,一个好的工具不一定要提高你的生产力:有时你最喜欢的命令也可以是能让你最快乐的命令。你的工作是找到自己喜欢的命令,用它们来改变世界。
|
||||
|
||||
玩得愉快!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/productivity-tools-linux-terminal
|
||||
|
||||
作者:[Alan Smithee][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/alansmithee
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY (Computer screen with files or windows open)
|
||||
[2]: https://opensource.com/users/ksonney
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_2-1.png
|
||||
[4]: https://opensource.com/article/20/1/sync-files-syncthing
|
||||
[5]: https://opensource.com/article/20/1/configuration-management-stow
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_3-1.png
|
||||
[7]: https://opensource.com/article/20/1/sync-email-offlineimap
|
||||
[8]: https://opensource.com/article/17/11/how-use-cron-linux
|
||||
[9]: https://opensource.com/article/20/1/organize-email-notmuch
|
||||
[10]: https://opensource.com/article/20/1/vim-email-calendar
|
||||
[11]: https://opensource.com/article/20/1/emacs-mail-calendar
|
||||
[12]: https://opensource.com/sites/default/files/uploads/productivity_5-1.png
|
||||
[13]: https://tools.ietf.org/html/rfc5545
|
||||
[14]: https://opensource.com/article/20/1/open-source-calendar
|
||||
[15]: https://opensource.com/article/20/1/sync-contacts-locally
|
||||
[16]: https://opensource.com/alternatives/google-calendar
|
||||
[17]: https://opensource.com/sites/default/files/uploads/productivity_7-1.png
|
||||
[18]: https://opensource.com/article/20/1/open-source-to-do-list
|
||||
[19]: https://opensource.com/article/20/1/python-journal
|
||||
[20]: https://opensource.com/sites/default/files/uploads/productivity_9-1.png
|
||||
[21]: https://opensource.com/article/20/1/open-source-chat-tool
|
||||
[22]: https://opensource.com/article/20/1/tweet-terminal-rainbow-stream
|
||||
[23]: https://opensource.com/sites/default/files/uploads/productivity_13-1.png
|
||||
[24]: https://opensource.com/article/20/1/open-source-reddit-client
|
||||
[25]: https://opensource.com/article/20/1/open-source-rss-feed-reader
|
||||
[26]: https://opensource.com/article/20/1/open-source-weather-forecast
|
||||
[27]: https://opensource.com/article/20/1/vim-task-list-reddit-twitter
|
||||
[28]: https://opensource.com/article/20/1/emacs-social-track-todo-list
|
||||
[29]: https://opensource.com/sites/default/files/uploads/productivity_14-1.png
|
||||
[30]: https://opensource.com/article/20/1/tmux-console
|
||||
[31]: https://opensource.com/article/20/1/multiple-consoles-twin
|
||||
Reference in New Issue
Block a user