คำสั่ง date

$ date --help
Usage: date [OPTION]... [+FORMAT]
  or:  date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
Display the current time in the given FORMAT, or set the system date.

Mandatory arguments to long options are mandatory for short options too.
  -d, --date=STRING         display time described by STRING, not 'now'
  -f, --file=DATEFILE       like --date once for each line of DATEFILE
  -I[TIMESPEC], --iso-8601[=TIMESPEC]  output date/time in ISO 8601 format.
                            TIMESPEC='date' for date only (the default),
                            'hours', 'minutes', 'seconds', or 'ns' for date
                            and time to the indicated precision.
  -r, --reference=FILE      display the last modification time of FILE
  -R, --rfc-2822            output date and time in RFC 2822 format.
                            Example: Mon, 07 Aug 2006 12:34:56 -0600
      --rfc-3339=TIMESPEC   output date and time in RFC 3339 format.
                            TIMESPEC='date', 'seconds', or 'ns' for
                            date and time to the indicated precision.
                            Date and time components are separated by
                            a single space: 2006-08-07 12:34:56-06:00
  -s, --set=STRING          set time described by STRING
  -u, --utc, --universal    print or set Coordinated Universal Time (UTC)
      --help     display this help and exit
      --version  output version information and exit

FORMAT controls the output.  Interpreted sequences are:

  %%   a literal %
  %a   locale's abbreviated weekday name (e.g., Sun)
  %A   locale's full weekday name (e.g., Sunday)
  %b   locale's abbreviated month name (e.g., Jan)
  %B   locale's full month name (e.g., January)
  %c   locale's date and time (e.g., Thu Mar  3 23:05:25 2005)
  %C   century; like %Y, except omit last two digits (e.g., 20)
  %d   day of month (e.g., 01)
  %D   date; same as %m/%d/%y
  %e   day of month, space padded; same as %_d
  %F   full date; same as %Y-%m-%d
  %g   last two digits of year of ISO week number (see %G)
  %G   year of ISO week number (see %V); normally useful only with %V
  %h   same as %b
  %H   hour (00..23)
  %I   hour (01..12)
  %j   day of year (001..366)
  %k   hour, space padded ( 0..23); same as %_H
  %l   hour, space padded ( 1..12); same as %_I
  %m   month (01..12)
  %M   minute (00..59)
  %n   a newline
  %N   nanoseconds (000000000..999999999)
  %p   locale's equivalent of either AM or PM; blank if not known
  %P   like %p, but lower case
  %r   locale's 12-hour clock time (e.g., 11:11:04 PM)
  %R   24-hour hour and minute; same as %H:%M
  %s   seconds since 1970-01-01 00:00:00 UTC
  %S   second (00..60)
  %t   a tab
  %T   time; same as %H:%M:%S
  %u   day of week (1..7); 1 is Monday
  %U   week number of year, with Sunday as first day of week (00..53)
  %V   ISO week number, with Monday as first day of week (01..53)
  %w   day of week (0..6); 0 is Sunday
  %W   week number of year, with Monday as first day of week (00..53)
  %x   locale's date representation (e.g., 12/31/99)
  %X   locale's time representation (e.g., 23:13:48)
  %y   last two digits of year (00..99)
  %Y   year
  %z   +hhmm numeric time zone (e.g., -0400)
  %:z  +hh:mm numeric time zone (e.g., -04:00)
  %::z  +hh:mm:ss numeric time zone (e.g., -04:00:00)
  %:::z  numeric time zone with : to necessary precision (e.g., -04, +05:30)
  %Z   alphabetic time zone abbreviation (e.g., EDT)

By default, date pads numeric fields with zeroes.
The following optional flags may follow '%':

  -  (hyphen) do not pad the field
  _  (underscore) pad with spaces
  0  (zero) pad with zeros
  ^  use upper case if possible
  #  use opposite case if possible

After any flags comes an optional field width, as a decimal number;
then an optional modifier, which is either
E to use the locale's alternate representations if available, or
O to use the locale's alternate numeric symbols if available.

Examples:
Convert seconds since the epoch (1970-01-01 UTC) to a date
  $ date --date='@2147483647'

Show the time on the west coast of the US (use tzselect(1) to find TZ)
  $ TZ='America/Los_Angeles' date

Show the local time for 9AM next Friday on the west coast of the US
  $ date --date='TZ="America/Los_Angeles" 09:00 next Fri'

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
For complete documentation, run: info coreutils 'date invocation'
$ date --version
date (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David MacKenzie.

ตัวอย่าง

Open a terminal application and type the following command:

$ date
Tue Feb  7 15:23:13 +07 2023

format the date

$ date +"%y-%m-%d"
23-02-07
$ date +"%Y-%m-%d"
2023-02-07

Simply display the current time on Linux:

]$ date "+%T"
15:24:15

To print the date of the day before yesterday, run:

$ date --date='2 days ago'
Sun Feb  5 15:25:37 +07 2023

Want to see the day of year of Christmas in the current year? Try:

$ date --date='25 Dec' +%j
359

Display the current full month name and the day of the month:

$ date '+%B %d'
February 07

if-else in Shell Scripts

How to use if-else in shell script

It is easy to see the syntax of a function and believe you know how to use it. But it is always a better choice to understand a function through examples because they help you understand the role that different aspects of a function play.

Here are some useful examples of if-else in shell scripts to give you a better idea of how to use this tool.

CommandDescription
&&Logical AND
$0Argument 0 i.e. the command that’s used to run the script
$1First argument (change number to access further arguments)
-eqEquality check
-neInequality check
-ltLess Than
-leLess Than or Equal
-gtGreater Than
-geGreater Than or Equal

1. Using if-else to check whether two numbers are equal

When trying to understand the working of a function like if-else in a shell script, it is good to start things simple. Here, we initialize two variables a and b, then use the if-else function to check if the two variables are equal. The bash script should look as follows for this task.

#!/bin/bash
m=1
n=2

if [ $n -eq $m ]
then
        echo "Both variables are the same"
else
        echo "Both variables are different"
fi

Output:

Both variables are different

2. Using if-else to compare two values

The more common use of if-else in shell scripts is for comparing two values. Comparing a variable against another variable or a fixed value helps is used in a variety of cases by all sorts of programmers.

For the sake of this example, we will be initializing two variables and using the if-else function to find the variable which is greater than the other.

#!/bin/bash
a=2
b=7
if [ $a -ge $b ]
then
  echo "The variable 'a' is greater than the variable 'b'."
else
  echo "The variable 'b' is greater than the variable 'a'."
fi

Output:

The variable 'b' is greater than the variable 'a'.

3. Using if-else to check whether a number is even

Sometimes we come across situations where we need to deal with and differentiate between even and odd numbers. This can be done with if-else in shell scripts if we take the help of the modulus operator.

The modulus operator divides a number with a divisor and returns the remainder.

As we know all even numbers are a multiple of 2, we can use the following shell script to check for us whether a number is even or odd.

#!/bin/bash
n=10
if [ $((n%2))==0 ]
then
  echo "The number is even."
else
  echo "The number is odd."
fi

Output:

The number is even

As you can see, we’ve enclosed a part of the condition within double brackets. That’s because we need the modulus operation to be performed before the condition is checked.

Also, enclosing in double brackets runs statements in C-style allowing you to process some C-style commands within bash scripts.

4. Using if-else as a simple password prompt

The if-else function is known for its versatility and range of application. In this example, we will use if-else in shell script to make the interface for a password prompt.

To do this, we will ask the user to enter the password and store it in the variable pass.

If it matches the pre-defined password, which is ‘password’ in this example, the user will get the output as -“The password is correct”.

Else, the shell script will tell the user that the password was incorrect and ask them to try again.

#!/bin/bash
echo "Enter password"
read pass
if [ $pass="password" ]
then
  echo "The password is correct."
else
  echo "The password is incorrect, try again."
fi

5. นับจำนวนไฟล์ว่าเท่ากับจำนวนที่กำหนดหรือไม่

#!/bin/bash
a=NUM_FILE=`find . -type f -print | wc -l`
b=4
if [ $a -eq $b ]
then
  echo "Exactly the same."
else
  echo "Wrong number"
fi

6. start, stop process

ถ้า process ไม่ได้รันอยู่ ให้ start process

#!/bin/bash

a=`ps -ef | grep PROCESS_NAME | wc -l`
b=1

if [ $a -gt $b ]
then
  echo "Found existing process"
else
  echo "Not found existing, START PROCESS_NAME"
  start.sh
fi

ถ้า process รันอยู่ ให้ stop process

#!/bin/bash

a=`ps -ef | grep PROCESS_NAME | wc -l`
b=1

if [ $a -gt $b ]
then
  echo "Found existing, STOP PROCESS_NAME "
  stop.sh
else
  echo "Process not found"
fi

คำสั่ง pgrep

ทดสอบบน Red Hat 7.7

The pgrep command allows a user to find process IDs in the running program in the system’s current state.

$ pgrep --version
pgrep from procps-ng 3.3.10
$ pgrep --help

Usage:
 pgrep [options] <pattern>

Options:
 -d, --delimiter <string>  specify output delimiter
 -l, --list-name           list PID and process name
 -a, --list-full           list PID and full command line
 -v, --inverse             negates the matching
 -w, --lightweight         list all TID
 -c, --count               count of matching processes
 -f, --full                use full process name to match
 -g, --pgroup <PGID,...>   match listed process group IDs
 -G, --group <GID,...>     match real group IDs
 -n, --newest              select most recently started
 -o, --oldest              select least recently started
 -P, --parent <PPID,...>   match only child processes of the given parent
 -s, --session <SID,...>   match session IDs
 -t, --terminal <tty,...>  match by controlling terminal
 -u, --euid <ID,...>       match by effective IDs
 -U, --uid <ID,...>        match by real IDs
 -x, --exact               match exactly with the command name
 -F, --pidfile <file>      read PIDs from file
 -L, --logpidfile          fail if PID file is not locked
 --ns <PID>                match the processes that belong to the same
                           namespace as <pid>
 --nslist <ns,...>         list which namespaces will be considered for
                           the --ns option.
                           Available namespaces: ipc, mnt, net, pid, user, uts

 -h, --help     display this help and exit
 -V, --version  output version information and exit

For more details see pgrep(1).

ตัวอย่าง

หา process ID ของ nginx

$ pgrep nginx
1085
1086

specify output delimiter ด้วย -d

$ pgrep -d: nginx
1085:1086

match exactly with the command name ด้วย -x

$ pgrep -x nginx
1085
1086

หา process ID จาก user name

$ pgrep -u jack

Markdig – rendering the Markdown

ติดตั้ง Markdig

PM> NuGet\Install-Package Markdig -Version 0.30.4

Usage

The main entry point for the API is the Markdig.Markdown class:

By default, without any options, Markdig is using the plain CommonMark parser:

using Markdig;

var result = Markdown.ToHtml("This is a text with some *emphasis*");
Console.WriteLine(result);   // prints: <p>This is a text with some <em>emphasis</em></p>

In order to activate most of all advanced extensions (except Emoji, SoftLine as HardLine, Bootstrap, YAML Front Matter, JiraLinks and SmartyPants)

using Markdig;

// Configure the pipeline with all advanced extensions active
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);

Python – GPG

ทดสอบบน Ubuntu 20.04.5 LTS ใน WSL 2

  1. Generate a key
  2. Export keys
  3. Import keys
  4. List keys
  5. Encrypt a string
  6. Decrypt a string
  7. Encrypt a file
  8. Decrypt a file

Installation

ติดตั้ง gnupg (น่าจะติดตั้งอยู่แล้ว)

sudo apt-get install gnupg 
$ gpg --version
gpg (GnuPG) 2.2.19
libgcrypt 1.8.5
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /home/jack/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

ติดตั้ง python-gnupg

pip install python-gnupg

1. Generate a key

import os
import gnupg

os.system('rm -rf /home/jack/gpghome')
os.system('mkdir  /home/jack/gpghome')

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
input_data = gpg.gen_key_input(
    key_length=4096,
    name_email='mr.phaisarn@gmail.com',
    passphrase='my passphrase')
key = gpg.gen_key(input_data)
print(key)
84511C0301E2D51E59D79C91B5432E86F4B8925A

2. Export keys

export ค่า public key และ private key ไว้ในไฟล์ mykeyfile.asc

import gnupg

key='84511C0301E2D51E59D79C91B5432E86F4B8925A'

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
ascii_armored_public_keys = gpg.export_keys(key,passphrase='my passphrase')
ascii_armored_private_keys = gpg.export_keys(key, True, passphrase='my passphrase')
with open('mykeyfile.asc', 'w') as f:
    f.write(ascii_armored_public_keys)
    f.write(ascii_armored_private_keys)
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGNqDu4BEADY6n5U0Fs4YBhAejiPZu5hI5i3oYbscK5xQSSXvgkUwoQkmHKQ
JVv+Chq4+jCguBSlmVXXMNnk45F7OhjuxpfrXDSxQPivwchXTh0117UEtTi5jE2s
eZTP5fMSdHomdD4NgU9PfSUiSPNH/PGnSQ8AFstFdFff846ry+dPu3XJdbkkVtEP
Cbv6idGCa2u/ZMukj2o2ZbvOXNVj1M5RFOpqJ6m52UQXA1W8S/Qr3g7gJ41jTWE3
oOP1oSfw5IbuO6yTrhOjwELTM2BexXwUAEtW59A8e+1JVh1xtbiTRxmnC+WHZ1T1
RQ9a7rFbFyqmboZ5RE8wUX7SsklzPyXtZhCnsFfBt3OVJNyD5hPoZ4qq7ihGeIIa
OD2g2VDu+uHeJg4Vqd8YcafFruLs0WR0BAdliYHClhhGSTQ2mFK7jQDfAVZYuFhZ
kKqd7WV7++e/oyLViWxDvhBN1XQ7Wbw5o1hkgeH6cyFg9nX/psVecXCriOJJUyVh
AKeFypLgfUiXkNoNuiWIcyJer55wIzjV0oTcLmHLtedh4Bh0+qvI+EI2UnKW2Ih0
Xas9jE3nx97T5365MD7hDjjm7sqmbg3xbih2VXUC+WjPuaisqbGgM/3vO06VA2A4
jg3j1SUm0N4IN8LSFzmAtvoSc5kvHDzTgySCYwlC3YowjKPciMu24jfjXwARAQAB
tClBdXRvZ2VuZXJhdGVkIEtleSA8bXIucGhhaXNhcm5AZ21haWwuY29tPokCTgQT
AQoAOBYhBIRRHAMB4tUeWdeckbVDLob0uJJaBQJjag7uAhsvBQsJCAcCBhUKCQgL
AgQWAgMBAh4BAheAAAoJELVDLob0uJJaL1AP+QEa1Uc1etOnSlz8V6IV5vcpPn0i
6T1cAAb0yfHELKScL4zC6oPq2AyWTTJUT9T/qiHtWi38bM90fkNfefpMdMHeh0TQ
GsTBeAO5YdF+I5GERib2m1vKJjaPVOQWaW0GhGo9fhI8TBdK0b4138JvHpdVsqub
/KbsoRXriXQxrYEy7bnl7Rsr2rYmRlFN5MGkxbVjmHYg1FJle6e6kCRD3sNs2juD
a1HDqYk6/MF6D5LlQ/o7tI53zeRrSAoOvY+yEnmp9a6Pb2X8vw3IGEzP12uad84X
sD2BhXLntie47svDqSbzOdPD0ON/W6M5DuCtWM9qwMrYHI8QyZqLG2sY7Mmz/2kQ
9R9+nU2O5I5sYWpkcW4olMEpe7jaiUNlq8tErIoOxDonc9tUrumoHOQvuxVodnSr
f1zJ5ypbE+v2Cz8MHw5hoBwQWokxZ8qrTo1zP3XvDe9tM5LykFOo8O1RJ1YmCJ58
qaHpC5jIZ/b+2/YKClG3XUxqFVBHLl5YvdfEXnJzOqRHLmakd7HyOgUbMBV0FtYf
E+ipdjfRPXsLh5cbF+HoVkScrcY+qmTSdN1m4c1ffLO419SAvhKgdC51VAd8UdoQ
ZYjx3vD06ghHO8sNyvuUL9z0XmuJykNxC1eVVnxgV8gf16OVymwMxcu5RPMIDtGS
0H7kHgfl3AmPCLrW
=m6l6
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PRIVATE KEY BLOCK-----

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
CY8IutY=
=6b0l
-----END PGP PRIVATE KEY BLOCK-----

3. Import keys

import gnupg
from pprint import pprint

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
key_data = open('mykeyfile.asc').read()
import_result = gpg.import_keys(key_data)
pprint(import_result.results)
[{'fingerprint': '84511C0301E2D51E59D79C91B5432E86F4B8925A',
  'ok': '0',
  'text': 'Not actually changed\n'},
 {'fingerprint': '84511C0301E2D51E59D79C91B5432E86F4B8925A',
  'ok': '0',
  'text': 'Not actually changed\n'},
 {'fingerprint': '84511C0301E2D51E59D79C91B5432E86F4B8925A',
  'ok': '16',
  'text': 'Not actually changed\nContains private key\n'}]

4. List keys

import gnupg
from pprint import pprint

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
public_keys = gpg.list_keys()
private_keys = gpg.list_keys(True)
print('public keys:')
pprint(public_keys)
print('private keys:')
pprint(private_keys)
public keys:
[{'algo': '1',
  'cap': 'escaESCA',
  'compliance': '23',
  'curve': '',
  'date': '1667895022',
  'dummy': '',
  'expires': '',
  'fingerprint': '84511C0301E2D51E59D79C91B5432E86F4B8925A',
  'flag': '',
  'hash': '',
  'issuer': '',
  'keygrip': 'AADC0ABF3CA1285034094D0381E0142B513D5514',
  'keyid': 'B5432E86F4B8925A',
  'length': '4096',
  'origin': '0',
  'ownertrust': 'u',
  'sig': '',
  'sigs': [],
  'subkeys': [],
  'token': '',
  'trust': 'u',
  'type': 'pub',
  'uids': ['Autogenerated Key <mr.phaisarn@gmail.com>'],
  'updated': ''}]
private keys:
[{'algo': '1',
  'cap': 'escaESCA',
  'compliance': '23',
  'curve': '',
  'date': '1667895022',
  'dummy': '',
  'expires': '',
  'fingerprint': '84511C0301E2D51E59D79C91B5432E86F4B8925A',
  'flag': '',
  'hash': '',
  'issuer': '',
  'keygrip': 'AADC0ABF3CA1285034094D0381E0142B513D5514',
  'keyid': 'B5432E86F4B8925A',
  'length': '4096',
  'origin': '0',
  'ownertrust': 'u',
  'sig': '',
  'sigs': [],
  'subkeys': [],
  'token': '+',
  'trust': 'u',
  'type': 'sec',
  'uids': ['Autogenerated Key <mr.phaisarn@gmail.com>'],
  'updated': ''}]

5. Encrypt a string

import gnupg

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
unencrypted_string = 'Who are you? How did you get in my house?'
encrypted_data = gpg.encrypt(unencrypted_string, 'mr.phaisarn@gmail.com')
encrypted_string = str(encrypted_data)

print('ok: ', encrypted_data.ok)
print('status: ', encrypted_data.status)
print('stderr: ', encrypted_data.stderr)
print('unencrypted_string: ', unencrypted_string)
print('encrypted_string: ', encrypted_string)
ok:  True
status:  encryption ok
stderr:  gpg: WARNING: unsafe permissions on homedir '/home/jack/gpghome'
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 2
[GNUPG:] ENCRYPTION_COMPLIANCE_MODE 23
[GNUPG:] BEGIN_ENCRYPTION 2 9
[GNUPG:] END_ENCRYPTION

unencrypted_string:  Who are you? How did you get in my house?
encrypted_string:  -----BEGIN PGP MESSAGE-----

hQIMA7VDLob0uJJaAQ//czHG42eeN1rtFTo6qdvoHSa/B3uJNeFSobUi4gUCxceh
yVbZ0La8pnLMy2JmA2agYaOvC6OhAXfNOhPXV5jinMTvwGB+dKC1qaAYXMknQjyF
5whvmQeBbuQX8AoKxs7hAYmlQO8mrHDBoP2xSdY/AgLeqdlnbZNcDR+NIpoPJS8a
zr+KHYAhEyZT0Bm6FAw7DvhriB4nJRLeMLoIQKIJTN3ZeEdlcZAt5xYL24dZfz8/
4Qpn++ItqsCQfXJ1leJIIE/oB4E83/J4FZuS1xh7n9OomBT2fRG8hmGlSzFYepX/
jDzjApmA/R4HGd6BuJZdNy6SV2DERs2NlTRko98IDFdCIg2Jp7jsSGSZowsKD7z5
rIU110iwR6hRropsuX18jlRk6QM1Um+dSGbHXTUk1OzUDE5uC3hBZsB0s9M2q5DS
HN+EbyatT9hB9X5Obf7w9Vj+Jta9q5voL/riZ2d+GFr8oR0d594An7Dup12zBff/
kdV7DgibAqorCD1MvVePOpvYw2NdhukRluOsVtXySkcAGy8VssBLoW3kqilOvrhq
pCJUG157TnhKnYW0l4BJ7KVoNFwBGsJKzS0Drh5Iq6LmiqHsKv7neK9LkApDeehD
EhdNoGN79fPvEYmync2bbGbVq6F7czHADwVKqNv0aDxaCrFHASsSXkGNbqMQ+tnS
YgFfzEOmYoDR7UjEog/OrBJAnPSgDcwn3I0xuU3RtDaEvlHCt6aX+NHEyIUvsIe+
Don8uUXi4VkjO2uoCOyNgwndoigDuouh8NDv5DIWcKt+KMGPkgKEmfbOxJNA0Rl5
TK5E
=Jyon
-----END PGP MESSAGE-----

6. Decrypt a string

import gnupg

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
unencrypted_string = 'Who are you? How did you get in my house?'
encrypted_data = gpg.encrypt(unencrypted_string, 'mr.phaisarn@gmail.com')
encrypted_string = str(encrypted_data)
decrypted_data = gpg.decrypt(encrypted_string, passphrase='my passphrase')

print('ok: ', decrypted_data.ok)
print('status: ', decrypted_data.status)
print('stderr: ', decrypted_data.stderr)
print('decrypted string: ', decrypted_data.data)
ok:  True
status:  decryption ok
stderr:  gpg: WARNING: unsafe permissions on homedir '/home/jack/gpghome'
[GNUPG:] ENC_TO B5432E86F4B8925A 1 0
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
[GNUPG:] DECRYPTION_KEY 84511C0301E2D51E59D79C91B5432E86F4B8925A 84511C0301E2D51E59D79C91B5432E86F4B8925A u
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
gpg: encrypted with 4096-bit RSA key, ID B5432E86F4B8925A, created 2022-11-08
      "Autogenerated Key <mr.phaisarn@gmail.com>"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_COMPLIANCE_MODE 23
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1667895570
[GNUPG:] PLAINTEXT_LENGTH 41
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION

decrypted string:  b'Who are you? How did you get in my house?'

7. Encrypt a file

import gnupg

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
open('my-unencrypted.txt', 'w').write('You need to Google Venn diagram.')
with open('my-unencrypted.txt', 'rb') as f:
    status = gpg.encrypt_file(
        f, recipients=['mr.phaisarn@gmail.com'],
        output='my-encrypted.txt.gpg')

print('ok: ', status.ok)
print('status: ', status.status)
print('stderr: ', status.stderr)
ok:  True
status:  encryption ok
stderr:  gpg: WARNING: unsafe permissions on homedir '/home/jack/gpghome'
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 2
[GNUPG:] ENCRYPTION_COMPLIANCE_MODE 23
[GNUPG:] BEGIN_ENCRYPTION 2 9
[GNUPG:] END_ENCRYPTION
-----BEGIN PGP MESSAGE-----

hQIMA7VDLob0uJJaARAAhwNuaLm5/eSCV81Uw+H2E536AzzXm/yPxM0CIjLjYxnE
+GwgvBxJsYtuuwCElUfYkIKYNzAWOGGRje961Be3+g5kjFfphvl4I1Xzwb5RKdWa
i9raKNQ1/PLQ6Hr8Fc3yh08QcgLkihyRgVKZ3suTX+KRzWd3/SS8rjS27nigQk8C
IoIuwJIsBYpB8xbBDM+Sfo2XJm938Z7n9ZfdDiuO0hEWBo5qF85Vh0jY91BVyPqD
yGYcsivK/OqRG/VrPTrp01+2+jBn5HPZoPCnjEZdyJ3p+k/bnvAymKpKmPfEHrt3
4FwJ0EIfFROx6u2xBWhoRAhl5vLjIgRqccwEHD9+HrT3aFyeQhOKcQoV0TXy5Y0w
rYLRBny2oolCGW1NqZi43pjamQXXVpJLDjOsn8pzhdbFiSxUrFZj2WXET7ItQaVd
fQQnPxpOpj7LOOncLdZ0qfGMYjNNXGoKlaPfdtJy1yQlz8mUUdZZAjAdCpKpnfca
YxuFmzMy2gGBKsYYrLB2FH6HasRbjb5uQ1qO72vybuPWCBNkX5jgWHGLddNagxR7
9EwMnvu958Oy3TiFfrr7YKWPIOQXaLx8WsgXCCl2rFJKG4Hy81ZM5k7DDQzzQFGd
w+a5FWo/cthXm6qx2LSE2ByFyAerqwe/T/wkAYmrQLIJdxZIWxp5xsuPBS6W6oLS
WwEiSHXqJPjqKHKnZwS0W9kWq/68voNf03QlEkN0+Hm3PRmEFIJnpw19BtfQEoY3
Rv/XCQXE2G6NVMajvFj72fvFzTUUyVRa8m//nu2wg9vG5JMjJbThA8L8+5E=
=WZm8
-----END PGP MESSAGE-----

ถ้า import public key แล้วนำมาใช้ encrypt จะได้ error invalid recipient

ok:  False
status:  invalid recipient
stderr:  gpg: WARNING: unsafe permissions on homedir `/home/jack/gpghome'
gpg: EAECD251: There is no assurance this key belongs to the named user
[GNUPG:] INV_RECP 10 84511C0301E2D51E59D79C91B5432E86F4B8925A
gpg: [stdin]: encryption failed: Unusable public key

ให้เพิ่ม gpg.trust_keys()

import gnupg

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
gpg.trust_keys('84511C0301E2D51E59D79C91B5432E86F4B8925A', 'TRUST_ULTIMATE')
open('my-unencrypted.txt', 'w').write('You need to Google Venn diagram.')
with open('my-unencrypted.txt', 'rb') as f:
    status = gpg.encrypt_file(
        f, recipients='84511C0301E2D51E59D79C91B5432E86F4B8925A',
        output='encrypted.txt.gpg')

print('ok: ', status.ok)
print('status: ', status.status)
print('stderr: ', status.stderr)

8. Decrypt a file

import gnupg

gpg = gnupg.GPG(gnupghome='/home/jack/gpghome')
with open('my-encrypted.txt.gpg', 'rb') as f:
    status = gpg.decrypt_file(f, passphrase='my passphrase', output='my-decrypted.txt')

print('ok: ', status.ok)
print('status: ', status.status)
print('stderr: ', status.stderr)
ok:  True
status:  decryption ok
stderr:  gpg: WARNING: unsafe permissions on homedir '/home/jack/gpghome'
[GNUPG:] ENC_TO B5432E86F4B8925A 1 0
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
[GNUPG:] DECRYPTION_KEY 84511C0301E2D51E59D79C91B5432E86F4B8925A 84511C0301E2D51E59D79C91B5432E86F4B8925A u
[GNUPG:] KEY_CONSIDERED 84511C0301E2D51E59D79C91B5432E86F4B8925A 0
gpg: encrypted with 4096-bit RSA key, ID B5432E86F4B8925A, created 2022-11-08
      "Autogenerated Key <mr.phaisarn@gmail.com>"
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_COMPLIANCE_MODE 23
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1667895671
[GNUPG:] PLAINTEXT_LENGTH 32
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION

Ubuntu Package Management

Apt

The apt command is a powerful command-line tool, which works with Ubuntu’s Advanced Packaging Tool (APT) performing such functions as installation of new software packages, upgrade of existing software packages, updating of the package list index, and even upgrading the entire Ubuntu system.

Some examples of popular uses for the apt utility:

Install a Package: Installation of packages using the apt tool is quite simple. For example, to install the nmap network scanner, type the following:

sudo apt install nmap

Remove a Package: Removal of a package (or packages) is also straightforward. To remove the package installed in the previous example, type the following:

sudo apt remove nmap

auto remove package

sudo apt autoremove

OPTIMIZE

Optimizes the layout of Delta Lake data. Optionally optimize a subset of data or colocate data by column. If you do not specify colocation, bin-packing optimization is performed.

Syntax

OPTIMIZE table_name [WHERE predicate]
  [ZORDER BY (col_name1 [, ...] ) ]

Parameters

  • table_name – Identifies an existing Delta table. The name must not include a temporal specification.
  • WHERE – Optimize the subset of rows matching the given partition predicate. Only filters involving partition key attributes are supported.
  • ZORDER BY – Colocate column information in the same set of files. Co-locality is used by Delta Lake data-skipping algorithms to dramatically reduce the amount of data that needs to be read. You can specify multiple columns for ZORDER BY as a comma-separated list. However, the effectiveness of the locality drops with each additional column.

Examples

OPTIMIZE delta.`/data/events`

OPTIMIZE events

OPTIMIZE events WHERE date >= '2022-11-18'

OPTIMIZE events
WHERE date >= current_timestamp() - INTERVAL 1 day
ZORDER BY (eventType)

VACUUM

VACUUM table_name [RETAIN num HOURS] [DRY RUN]

Parameters

  • table_name – Identifies an existing Delta table. The name must not include a temporal specification.
  • RETAIN num HOURS – The retention threshold.
  • DRY RUN – Return a list of up to 1000 files to be deleted.

แสดงรายชื่อไฟล์ที่จะถูกลบ

VACUUM table_name RETAIN 720 HOURS DRY RUN

ทำการลบไฟล์

VACUUM table_name RETAIN 720 HOURS
1 day24 HOURS
1 week168 HOURS
2 week336 HOURS
30 days720 HOURS

Configure data retention for time travel

To time travel to a previous version, you must retain both the log and the data files for that version.

The data files backing a Delta table are never deleted automatically; data files are deleted only when you run VACUUMVACUUM does not delete Delta log files; log files are automatically cleaned up after checkpoints are written.

By default you can time travel to a Delta table up to 30 days old unless you have:

  • Run VACUUM on your Delta table.
  • Changed the data or log file retention periods using the following table properties:
    • delta.logRetentionDuration = "interval <interval>": controls how long the history for a table is kept. The default is interval 30 days.Each time a checkpoint is written, Databricks automatically cleans up log entries older than the retention interval. If you set this config to a large enough value, many log entries are retained. This should not impact performance as operations against the log are constant time. Operations on history are parallel but will become more expensive as the log size increases.
    • delta.deletedFileRetentionDuration = "interval <interval>": controls how long ago a file must have been deleted before being a candidate for VACUUM. The default is interval 7 days.To access 30 days of historical data even if you run VACUUM on the Delta table, set delta.deletedFileRetentionDuration = "interval 30 days". This setting may cause your storage costs to go up.

ถ้ารัน VACUUM เลย data files ที่เกิน 7 วันจะถูกลบ

ถ้าจะเก็บ data files ให้มากกว่า 7 วัน โดยไม่ต้องมาคอยกำหนดค่า RETAIN num HOURS ให้ไป SET delta.deletedFileRetentionDuration ก่อน แล้วค่อยรัน VACUUM

SET and UNSET TBLPROPERTIES

ALTER TABLE table_name
   { RENAME TO clause |
     ADD COLUMN clause |
     ALTER COLUMN clause |
     DROP COLUMN clause |
     RENAME COLUMN clause |
     ADD CONSTRAINT clause |
     DROP CONSTRAINT clause |
     ADD PARTITION clause |
     DROP PARTITION clause |
     RENAME PARTITION clause |
     RECOVER PARTITIONS clause |
     SET TBLPROPERTIES clause |
     UNSET TBLPROPERTIES clause |
     SET SERDE clause |
     SET LOCATION clause |
     SET OWNER TO clause }

Example

ALTER TABLE dbx.tab1 SET TBLPROPERTIES ('delta.logRetentionDuration' = 'interval 30 days');
ALTER TABLE dbx.tab1 SET TBLPROPERTIES ('delta.deletedFileRetentionDuration' = 'interval 30 days');

ALTER TABLE dbx.tab1 UNSET TBLPROPERTIES ('delta.deletedFileRetentionDuration');