How to: Search in Linux, How to: Use grep command, How to: Use grep to search

“grep” is very useful when searching text.

On Microsoft Windows, we can use “dngrep” to achieve similar results

grep command

grep is a command-line utility for searching plain-text data sets for lines that match a regular expression. Its name comes from the ed command g/re/p (globally search a regular expression and print), which has the same effect: doing a global search with the regular expression and printing all matching lines. [1]

Some basic grep usage

grep 'test' filename #Search test in file filename
grep 'test' file1 file2 #Search test from file1 and file2
cat filename | grep 'test' #Print out content from filename then search for test
grep --color=never 'test' filename #Search test from filename and don't highlight the results
grep --color=auto 'test' filename #Search test from filename and displays color in the output unless the output is piped to a command, or redirected to a file
grep --color=always 'test' filename #Search test from filename and highlight the matched string/results
grep 'test' test.txt
grep ‘test’ test.txt
grep --color[auto/never/always] 'test' test.txt
grep –color[auto/never/always] ‘test’ test.txt

Simple search

Search www from /etc/passwd file

grep www /etc/passwd
grep www /etc/passwd
grep www /etc/passwd

Search www from /etc/passwd file with case insensitive switch “-i” (Means WWW www WWw wwW WwW wWw will be included in the results as well)

grep -i 'www' /etc/passwd

Search recursively

Search all files from a folder for a text

e.g. Search “configured” from “/etc” folder

grep -r 'disabled' /etc
 
or
 
grep -R 'disabled' /etc
grep -r 'disabled' /etc
grep -r ‘disabled’ /etc

To eliminate file name

grep -hr 'disabled' /etc
 
or
 
grep -h -r 'disabled' /etc
grep -hr 'disabled' /etc
grep -hr ‘disabled’ /etc

Search with “-w” match only whole words switch

grep -w 'word' filename
grep -w test test.txt
grep -w test test.txt

Use egrep to search two different words

egrep -w 'word1|word2' filename
egrep 'test|testaaa' test.txt
egrep ‘test|testaaa’ test.txt
egrep -w 'test|testaaa' test.txt
egrep -w ‘test|testaaa’ test.txt

Show count of matching results & Show number of the row the results at in the file

#Show count of matching results
grep -c -w test test.txt
#Show number of the row the results at in the file
grep -n -w test test.txt
Show count of matching results, Show number of the row the results at in the file
Show count of matching results, Show number of the row the results at in the file

Search with inverse match (Exclude the string)

grep -v excludeWord filename
grep -v text test.txt
grep -v text test.txt
grep -vn text test.txt
grep -vn text test.txt

Use grep with Linux pipeline

grep -i 'searchTerm' command
command | grep -i 'model'

Show hard drive name

dmesg | egrep '(s|h)d[a-z]'

Show cpu model

#With pipeline
cat /proc/cpuinfo | grep -i 'Model'
 
#Without pipeine
grep -i 'Model' /proc/cpuinfo
grep with/without Linux pipeline
grep with/without Linux pipeline

List files which includes the search term

Search all “.txt” files which contains “test”

grep -l 'test' *.txt
grep -l 'test' *.txt
grep -l ‘test’ *.txt

Some switches of grep command

-cCount of occurrence
-hRemove file name and path from results
-iCase insensitive
-lPrint only names of FILEs with selected lines
-nPrint line numbers
-RRecursive search, obey all symbolic links
-rRecursive search all folders
-vReverse match
-wMatch only whole words
–colorApply/Disable color scheme for search results

Help page of grep

Usage: grep [OPTION]... PATTERNS [FILE]...
Search for PATTERNS in each FILE.
Example: grep -i 'hello world' menu.h main.c
PATTERNS can contain multiple patterns separated by newlines.
Pattern selection and interpretation:
  -E, --extended-regexp     PATTERNS are extended regular expressions
  -F, --fixed-strings       PATTERNS are strings
  -G, --basic-regexp        PATTERNS are basic regular expressions
  -P, --perl-regexp         PATTERNS are Perl regular expressions
  -e, --regexp=PATTERNS     use PATTERNS for matching
  -f, --file=FILE           take PATTERNS from FILE
  -i, --ignore-case         ignore case distinctions in patterns and data
      --no-ignore-case      do not ignore case distinctions (default)
  -w, --word-regexp         match only whole words
  -x, --line-regexp         match only whole lines
  -z, --null-data           a data line ends in 0 byte, not newline
Miscellaneous:
  -s, --no-messages         suppress error messages
  -v, --invert-match        select non-matching lines
  -V, --version             display version information and exit
      --help                display this help text and exit
Output control:
  -m, --max-count=NUM       stop after NUM selected lines
  -b, --byte-offset         print the byte offset with output lines
  -n, --line-number         print line number with output lines
      --line-buffered       flush output on every line
  -H, --with-filename       print file name with output lines
  -h, --no-filename         suppress the file name prefix on output
      --label=LABEL         use LABEL as the standard input file name prefix
  -o, --only-matching       show only nonempty parts of lines that match
  -q, --quiet, --silent     suppress all normal output
      --binary-files=TYPE   assume that binary files are TYPE;
                            TYPE is 'binary', 'text', or 'without-match'
  -a, --text                equivalent to --binary-files=text
  -I                        equivalent to --binary-files=without-match
  -d, --directories=ACTION  how to handle directories;
                            ACTION is 'read', 'recurse', or 'skip'
  -D, --devices=ACTION      how to handle devices, FIFOs and sockets;
                            ACTION is 'read' or 'skip'
  -r, --recursive           like --directories=recurse
  -R, --dereference-recursive  likewise, but follow all symlinks
      --include=GLOB        search only files that match GLOB (a file pattern)
      --exclude=GLOB        skip files that match GLOB
      --exclude-from=FILE   skip files that match any file pattern from FILE
      --exclude-dir=GLOB    skip directories that match GLOB
  -L, --files-without-match  print only names of FILEs with no selected lines
  -l, --files-with-matches  print only names of FILEs with selected lines
  -c, --count               print only a count of selected lines per FILE
  -T, --initial-tab         make tabs line up (if needed)
  -Z, --null                print 0 byte after FILE name
Context control:
  -B, --before-context=NUM  print NUM lines of leading context
  -A, --after-context=NUM   print NUM lines of trailing context
  -C, --context=NUM         print NUM lines of output context
  -NUM                      same as --context=NUM
      --color[=WHEN],
      --colour[=WHEN]       use markers to highlight the matching strings;
                            WHEN is 'always', 'never', or 'auto'
  -U, --binary              do not strip CR characters at EOL (MSDOS/Windows)
When FILE is '-', read standard input.  With no FILE, read '.' if
recursive, '-' otherwise.  With fewer than two FILEs, assume -h.
Exit status is 0 if any line (or file if -L) is selected, 1 otherwise;
if any error occurs and -q is not given, the exit status is 2.
Report bugs to: [email protected]
GNU grep home page: <http://www.gnu.org/software/grep/>
General help using GNU software: <https://www.gnu.org/gethelp/>

man page of grep

GREP(1)                                                                                                     User Commands                                                                                                     GREP(1)
NAME
       grep, egrep, fgrep, rgrep - print lines that match patterns
SYNOPSIS
       grep [OPTION...] PATTERNS [FILE...]
       grep [OPTION...] -e PATTERNS ... [FILE...]
       grep [OPTION...] -f PATTERN_FILE ... [FILE...]
DESCRIPTION
       grep  searches  for  PATTERNS  in  each FILE.  PATTERNS is one or more patterns separated by newline characters, and grep prints each line that matches a pattern.  Typically PATTERNS should be quoted when grep is used in a
       shell command.
       A FILE of “-” stands for standard input.  If no FILE is given, recursive searches examine the working directory, and nonrecursive searches read standard input.
       In addition, the variant programs egrep, fgrep and rgrep are the same as grep -E, grep -F, and grep -r, respectively.  These variants are deprecated, but are provided for backward compatibility.
OPTIONS
   Generic Program Information
       --help Output a usage message and exit.
       -V, --version
              Output the version number of grep and exit.
   Pattern Syntax
       -E, --extended-regexp
              Interpret PATTERNS as extended regular expressions (EREs, see below).
       -F, --fixed-strings
              Interpret PATTERNS as fixed strings, not regular expressions.
       -G, --basic-regexp
              Interpret PATTERNS as basic regular expressions (BREs, see below).  This is the default.
       -P, --perl-regexp
              Interpret PATTERNS as Perl-compatible regular expressions (PCREs).  This option is experimental when combined with the -z (--null-data) option, and grep -P may warn of unimplemented features.
   Matching Control
       -e PATTERNS, --regexp=PATTERNS
              Use PATTERNS as the patterns.  If this option is used multiple times or is combined with the -f (--file) option, search for all patterns given.  This option can be used to protect a pattern beginning with “-”.
       -f FILE, --file=FILE
              Obtain patterns from FILE, one per line.  If this option is used multiple times or is combined with the -e (--regexp) option, search for all patterns given.  The empty file  contains  zero  patterns,  and  therefore
              matches nothing.
       -i, --ignore-case
              Ignore case distinctions in patterns and input data, so that characters that differ only in case match each other.
       --no-ignore-case
              Do  not ignore case distinctions in patterns and input data.  This is the default.  This option is useful for passing to shell scripts that already use -i, to cancel its effects because the two options override each
              other.
       -v, --invert-match
              Invert the sense of matching, to select non-matching lines.
       -w, --word-regexp
              Select only those lines containing matches that form whole words.  The test is that the matching substring must either be at the beginning of the line, or preceded by a non-word constituent character.  Similarly, it
              must be either at the end of the line or followed by a non-word constituent character.  Word-constituent characters are letters, digits, and the underscore.  This option has no effect if -x is also specified.
       -x, --line-regexp
              Select only those matches that exactly match the whole line.  For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
       -y     Obsolete synonym for -i.
   General Output Control
       -c, --count
              Suppress normal output; instead print a count of matching lines for each input file.  With the -v, --invert-match option (see below), count non-matching lines.
       --color[=WHEN], --colour[=WHEN]
              Surround the matched (non-empty) strings, matching lines, context lines, file names, line numbers, byte offsets, and separators (for fields and groups of context lines) with escape sequences to display them in color
              on the terminal.  The colors are defined by the environment variable GREP_COLORS.  The deprecated environment variable GREP_COLOR is still supported, but its setting does not have priority.  WHEN is  never,  always,
              or auto.
       -L, --files-without-match
              Suppress normal output; instead print the name of each input file from which no output would normally have been printed.  The scanning will stop on the first match.
       -l, --files-with-matches
              Suppress normal output; instead print the name of each input file from which output would normally have been printed.  The scanning will stop on the first match.
       -m NUM, --max-count=NUM
              Stop  reading  a  file  after  NUM  matching  lines.   If the input is standard input from a regular file, and NUM matching lines are output, grep ensures that the standard input is positioned to just after the last
              matching line before exiting, regardless of the presence of trailing context lines.  This enables a calling process to resume a search.  When grep stops after NUM matching lines,  it  outputs  any  trailing  context
              lines.  When the -c or --count option is also used, grep does not output a count greater than NUM.  When the -v or --invert-match option is also used, grep stops after outputting NUM non-matching lines.
       -o, --only-matching
              Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.
       -q, --quiet, --silent
              Quiet; do not write anything to standard output.  Exit immediately with zero status if any match is found, even if an error was detected.  Also see the -s or --no-messages option.
       -s, --no-messages
              Suppress error messages about nonexistent or unreadable files.
   Output Line Prefix Control
       -b, --byte-offset
              Print the 0-based byte offset within the input file before each line of output.  If -o (--only-matching) is specified, print the offset of the matching part itself.
       -H, --with-filename
              Print the file name for each match.  This is the default when there is more than one file to search.
       -h, --no-filename
              Suppress the prefixing of file names on output.  This is the default when there is only one file (or only standard input) to search.
       --label=LABEL
              Display  input  actually  coming  from  standard input as input coming from file LABEL.  This can be useful for commands that transform a file's contents before searching, e.g., gzip -cd foo.gz | grep --label=foo -H
              'some pattern'.  See also the -H option.
       -n, --line-number
              Prefix each line of output with the 1-based line number within its input file.
       -T, --initial-tab
              Make sure that the first character of actual line content lies on a tab stop, so that the alignment of tabs looks normal.  This is useful with options that prefix their output to the actual content: -H,-n,  and  -b.
              In order to improve the probability that lines from a single file will all start at the same column, this also causes the line number and byte offset (if present) to be printed in a minimum size field width.
       -u, --unix-byte-offsets
              Report Unix-style byte offsets.  This switch causes grep to report byte offsets as if the file were a Unix-style text file, i.e., with CR characters stripped off.  This will produce results identical to running grep
              on a Unix machine.  This option has no effect unless -b option is also used; it has no effect on platforms other than MS-DOS and MS-Windows.
       -Z, --null
              Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name.  For example, grep -lZ outputs a zero byte after each file name instead of the  usual  newline.   This  option
              makes  the  output  unambiguous,  even  in  the presence of file names containing unusual characters like newlines.  This option can be used with commands like find -print0, perl -0, sort -z, and xargs -0 to process
              arbitrary file names, even those that contain newline characters.
   Context Line Control
       -A NUM, --after-context=NUM
              Print NUM lines of trailing context after matching lines.  Places a line containing a group separator (--) between contiguous groups of matches.  With the -o or --only-matching option,  this  has  no  effect  and  a
              warning is given.
       -B NUM, --before-context=NUM
              Print  NUM  lines  of  leading  context  before matching lines.  Places a line containing a group separator (--) between contiguous groups of matches.  With the -o or --only-matching option, this has no effect and a
              warning is given.
       -C NUM, -NUM, --context=NUM
              Print NUM lines of output context.  Places a line containing a group separator (--) between contiguous groups of matches.  With the -o or --only-matching option, this has no effect and a warning is given.
   File and Directory Selection
       -a, --text
              Process a binary file as if it were text; this is equivalent to the --binary-files=text option.
       --binary-files=TYPE
              If a file's data or metadata indicate that the file contains binary data, assume that the file is of type TYPE.  Non-text bytes indicate binary data; these are either output bytes that are improperly encoded for the
              current locale, or null input bytes when the -z option is not given.
              By  default, TYPE is binary, and grep suppresses output after null input binary data is discovered, and suppresses output lines that contain improperly encoded data.  When some output is suppressed, grep follows any
              output with a one-line message saying that a binary file matches.
              If TYPE is without-match, when grep discovers null input binary data it assumes that the rest of the file does not match; this is equivalent to the -I option.
              If TYPE is text, grep processes a binary file as if it were text; this is equivalent to the -a option.
              When type is binary, grep may treat non-text bytes as line terminators even without the -z option.  This means choosing binary versus text can affect whether a pattern matches a file.   For  example,  when  type  is
              binary the pattern q$ might match q immediately followed by a null byte, even though this is not matched when type is text.  Conversely, when type is binary the pattern . (period) might not match a null byte.
              Warning:  The -a option might output binary garbage, which can have nasty side effects if the output is a terminal and if the terminal driver interprets some of it as commands.  On the other hand, when reading files
              whose text encodings are unknown, it can be helpful to use -a or to set LC_ALL='C' in the environment, in order to find more matches even if the matches are unsafe for direct display.
       -D ACTION, --devices=ACTION
              If an input file is a device, FIFO or socket, use ACTION to process it.  By default, ACTION is read, which means that devices are read just as if they were ordinary files.  If ACTION is skip,  devices  are  silently
              skipped.
       -d ACTION, --directories=ACTION
              If  an  input  file  is  a  directory,  use ACTION to process it.  By default, ACTION is read, i.e., read directories just as if they were ordinary files.  If ACTION is skip, silently skip directories.  If ACTION is
              recurse, read all files under each directory, recursively, following symbolic links only if they are on the command line.  This is equivalent to the -r option.
       --exclude=GLOB
              Skip any command-line file with a name suffix that matches the pattern GLOB, using wildcard matching; a name suffix is either the whole name, or a trailing part that starts with  a  non-slash  character  immediately
              after  a  slash  (/) in the name.  When searching recursively, skip any subfile whose base name matches GLOB; the base name is the part after the last slash.  A pattern can use *, ?, and [...] as wildcards, and \ to
              quote a wildcard or backslash character literally.
       --exclude-from=FILE
              Skip files whose base name matches any of the file-name globs read from FILE (using wildcard matching as described under --exclude).
       --exclude-dir=GLOB
              Skip any command-line directory with a name suffix that matches the pattern GLOB.  When searching recursively, skip any subdirectory whose base name matches GLOB.  Ignore any redundant trailing slashes in GLOB.
       -I     Process a binary file as if it did not contain matching data; this is equivalent to the --binary-files=without-match option.
       --include=GLOB
              Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).
       -r, --recursive
              Read all files under each directory, recursively, following symbolic links only if they are on the command line.  Note that if no file operand is given, grep searches the working directory.  This  is  equivalent  to
              the -d recurse option.
       -R, --dereference-recursive
              Read all files under each directory, recursively.  Follow all symbolic links, unlike -r.
   Other Options
       --line-buffered
              Use line buffering on output.  This can cause a performance penalty.
       -U, --binary
              Treat  the  file(s)  as binary.  By default, under MS-DOS and MS-Windows, grep guesses whether a file is text or binary as described for the --binary-files option.  If grep decides the file is a text file, it strips
              the CR characters from the original file contents (to make regular expressions with ^ and $ work correctly).  Specifying -U overrules this guesswork, causing all files to be read and passed to the matching mechanism
              verbatim; if the file is a text file with CR/LF pairs at the end of each line, this will cause some regular expressions to fail.  This option has no effect on platforms other than MS-DOS and MS-Windows.
       -z, --null-data
              Treat  input and output data as sequences of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline.  Like the -Z or --null option, this option can be used with commands like sort -z to
              process arbitrary file names.
REGULAR EXPRESSIONS
       A regular expression is a pattern that describes a set of strings.  Regular expressions are constructed analogously to arithmetic expressions, by using various operators to combine smaller expressions.
       grep understands three different versions of regular expression syntax: “basic” (BRE), “extended” (ERE) and “perl” (PCRE).  In GNU grep there is no difference in available functionality between basic and extended syntaxes.
       In  other  implementations,  basic  regular  expressions  are  less  powerful.  The following description applies to extended regular expressions; differences for basic regular expressions are summarized afterwards.  Perl-
       compatible regular expressions give additional functionality, and are documented in pcresyntax(3) and pcrepattern(3), but work only if PCRE is available in the system.
       The fundamental building blocks are the regular expressions that match a single character.  Most characters, including all letters and digits, are regular expressions that match themselves.  Any meta-character with special
       meaning may be quoted by preceding it with a backslash.
       The period . matches any single character.  It is unspecified whether it matches an encoding error.
   Character Classes and Bracket Expressions
       A  bracket  expression  is  a  list  of characters enclosed by [ and ].  It matches any single character in that list.  If the first character of the list is the caret ^ then it matches any character not in the list; it is
       unspecified whether it matches an encoding error.  For example, the regular expression [0123456789] matches any single digit.
       Within a bracket expression, a range expression consists of two characters separated by a hyphen.  It matches any single character that sorts between the two characters, inclusive, using the locale's collating sequence and
       character  set.   For  example,  in  the  default  C  locale,  [a-d] is equivalent to [abcd].  Many locales sort characters in dictionary order, and in these locales [a-d] is typically not equivalent to [abcd]; it might be
       equivalent to [aBbCcDd], for example.  To obtain the traditional interpretation of bracket expressions, you can use the C locale by setting the LC_ALL environment variable to the value C.
       Finally, certain named classes of characters are predefined within bracket expressions, as follows.  Their names are self explanatory,  and  they  are  [:alnum:],  [:alpha:],  [:blank:],  [:cntrl:],  [:digit:],  [:graph:],
       [:lower:],  [:print:],  [:punct:],  [:space:], [:upper:], and [:xdigit:].  For example, [[:alnum:]] means the character class of numbers and letters in the current locale.  In the C locale and ASCII character set encoding,
       this is the same as [0-9A-Za-z].  (Note that the brackets in these class names are part of the symbolic names, and must be included in addition to the brackets delimiting the bracket expression.)  Most meta-characters lose
       their special meaning inside bracket expressions.  To include a literal ] place it first in the list.  Similarly, to include a literal ^ place it anywhere but first.  Finally, to include a literal - place it last.
   Anchoring
       The caret ^ and the dollar sign $ are meta-characters that respectively match the empty string at the beginning and end of a line.
   The Backslash Character and Special Expressions
       The  symbols \< and \> respectively match the empty string at the beginning and end of a word.  The symbol \b matches the empty string at the edge of a word, and \B matches the empty string provided it's not at the edge of
       a word.  The symbol \w is a synonym for [_[:alnum:]] and \W is a synonym for [^_[:alnum:]].
   Repetition
       A regular expression may be followed by one of several repetition operators:
       ?      The preceding item is optional and matched at most once.
       *      The preceding item will be matched zero or more times.
       +      The preceding item will be matched one or more times.
       {n}    The preceding item is matched exactly n times.
       {n,}   The preceding item is matched n or more times.
       {,m}   The preceding item is matched at most m times.  This is a GNU extension.
       {n,m}  The preceding item is matched at least n times, but not more than m times.
   Concatenation
       Two regular expressions may be concatenated; the resulting regular expression matches any string formed by concatenating two substrings that respectively match the concatenated expressions.
   Alternation
       Two regular expressions may be joined by the infix operator |; the resulting regular expression matches any string matching either alternate expression.
   Precedence
       Repetition takes precedence over concatenation, which in turn takes precedence over alternation.  A whole expression may be enclosed in parentheses to override these precedence rules and form a subexpression.
   Back-references and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring previously matched by the nth parenthesized subexpression of the regular expression.
   Basic vs Extended Regular Expressions
       In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, \+, \{, \|, \(, and \).
EXIT STATUS
       Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred.  However, if the -q or --quiet or --silent is used and a line is selected, the exit status is 0 even if an error
       occurred.
ENVIRONMENT
       The behavior of grep is affected by the following environment variables.
       The  locale  for category LC_foo is specified by examining the three environment variables LC_ALL, LC_foo, LANG, in that order.  The first of these variables that is set specifies the locale.  For example, if LC_ALL is not
       set, but LC_MESSAGES is set to pt_BR, then the Brazilian Portuguese locale is used for the LC_MESSAGES category.  The C locale is used if none of these environment variables are set, if the locale catalog is not installed,
       or if grep was not compiled with national language support (NLS).  The shell command locale -a lists locales that are currently available.
       GREP_OPTIONS
              This variable specifies default options to be placed in front of any explicit options.  As this causes problems when writing portable scripts, this feature will be removed in a future release of grep, and grep warns
              if it is used.  Please use an alias or script instead.
       GREP_COLOR
              This variable specifies the color used to highlight matched (non-empty) text.  It is deprecated in favor of GREP_COLORS, but still supported.  The mt, ms, and mc capabilities of GREP_COLORS have  priority  over  it.
              It  can only specify the color used to highlight the matching non-empty text in any matching line (a selected line when the -v command-line option is omitted, or a context line when -v is specified).  The default is
              01;31, which means a bold red foreground text on the terminal's default background.
       GREP_COLORS
              Specifies the colors and other attributes used to highlight various parts of the output.  Its value is a colon-separated list of capabilities that defaults to  ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36  with
              the rv and ne boolean capabilities omitted (i.e., false).  Supported capabilities are as follows.
              sl=    SGR  substring for whole selected lines (i.e., matching lines when the -v command-line option is omitted, or non-matching lines when -v is specified).  If however the boolean rv capability and the -v command-
                     line option are both specified, it applies to context matching lines instead.  The default is empty (i.e., the terminal's default color pair).
              cx=    SGR substring for whole context lines (i.e., non-matching lines when the -v command-line option is omitted, or matching lines when -v is specified).  If however the boolean rv capability and the  -v  command-
                     line option are both specified, it applies to selected non-matching lines instead.  The default is empty (i.e., the terminal's default color pair).
              rv     Boolean value that reverses (swaps) the meanings of the sl= and cx= capabilities when the -v command-line option is specified.  The default is false (i.e., the capability is omitted).
              mt=01;31
                     SGR  substring  for  matching  non-empty  text  in  any matching line (i.e., a selected line when the -v command-line option is omitted, or a context line when -v is specified).  Setting this is equivalent to
                     setting both ms= and mc= at once to the same value.  The default is a bold red text foreground over the current line background.
              ms=01;31
                     SGR substring for matching non-empty text in a selected line.  (This is only used when the -v command-line option is omitted.)  The effect of the sl= (or cx= if rv) capability remains active when  this  kicks
                     in.  The default is a bold red text foreground over the current line background.
              mc=01;31
                     SGR  substring for matching non-empty text in a context line.  (This is only used when the -v command-line option is specified.)  The effect of the cx= (or sl= if rv) capability remains active when this kicks
                     in.  The default is a bold red text foreground over the current line background.
              fn=35  SGR substring for file names prefixing any content line.  The default is a magenta text foreground over the terminal's default background.
              ln=32  SGR substring for line numbers prefixing any content line.  The default is a green text foreground over the terminal's default background.
              bn=32  SGR substring for byte offsets prefixing any content line.  The default is a green text foreground over the terminal's default background.
              se=36  SGR substring for separators that are inserted between selected line fields (:), between context line fields, (-), and between groups of adjacent lines when nonzero context is specified (--).  The default  is
                     a cyan text foreground over the terminal's default background.
              ne     Boolean  value  that prevents clearing to the end of line using Erase in Line (EL) to Right (\33[K) each time a colorized item ends.  This is needed on terminals on which EL is not supported.  It is otherwise
                     useful on terminals for which the back_color_erase (bce) boolean terminfo capability does not apply, when the chosen highlight colors do not affect the background, or when EL is too slow or  causes  too  much
                     flicker.  The default is false (i.e., the capability is omitted).
              Note that boolean capabilities have no =... part.  They are omitted (i.e., false) by default and become true when specified.
              See  the  Select Graphic Rendition (SGR) section in the documentation of the text terminal that is used for permitted values and their meaning as character attributes.  These substring values are integers in decimal
              representation and can be concatenated with semicolons.  grep takes care of assembling the result into a complete SGR sequence (\33[...m).  Common values to concatenate include 1 for bold, 4  for  underline,  5  for
              blink,  7  for  inverse,  39  for default foreground color, 30 to 37 for foreground colors, 90 to 97 for 16-color mode foreground colors, 38;5;0 to 38;5;255 for 88-color and 256-color modes foreground colors, 49 for
              default background color, 40 to 47 for background colors, 100 to 107 for 16-color mode background colors, and 48;5;0 to 48;5;255 for 88-color and 256-color modes background colors.
       LC_ALL, LC_COLLATE, LANG
              These variables specify the locale for the LC_COLLATE category, which determines the collating sequence used to interpret range expressions like [a-z].
       LC_ALL, LC_CTYPE, LANG
              These variables specify the locale for the LC_CTYPE category, which determines the type of characters, e.g., which characters are whitespace.  This category also determines the character encoding, that  is,  whether
              text is encoded in UTF-8, ASCII, or some other encoding.  In the C or POSIX locale, all characters are encoded as a single byte and every byte is a valid character.
       LC_ALL, LC_MESSAGES, LANG
              These variables specify the locale for the LC_MESSAGES category, which determines the language that grep uses for messages.  The default C locale uses American English messages.
       POSIXLY_CORRECT
              If  set, grep behaves as POSIX requires; otherwise, grep behaves more like other GNU programs.  POSIX requires that options that follow file names must be treated as file names; by default, such options are permuted
              to the front of the operand list and are treated as options.  Also, POSIX requires that unrecognized options be diagnosed as “illegal”, but since they are not really against the law the default is to  diagnose  them
              as “invalid”.  POSIXLY_CORRECT also disables _N_GNU_nonoption_argv_flags_, described below.
       _N_GNU_nonoption_argv_flags_
              (Here  N  is  grep's numeric process ID.)  If the ith character of this environment variable's value is 1, do not consider the ith operand of grep to be an option, even if it appears to be one.  A shell can put this
              variable in the environment for each command it runs, specifying which operands are the results of file name wildcard expansion and therefore should not be treated as options.  This behavior is available  only  with
              the GNU C library, and only when POSIXLY_CORRECT is not set.
NOTES
       This man page is maintained only fitfully; the full documentation is often more up-to-date.
COPYRIGHT
       Copyright 1998-2000, 2002, 2005-2020 Free Software Foundation, Inc.
       This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
BUGS
   Reporting Bugs
       Email  bug  reports to the bug-reporting address ⟨[email protected]⟩.  An email archive ⟨https://lists.gnu.org/mailman/listinfo/bug-grep⟩ and a bug tracker ⟨https://debbugs.gnu.org/cgi/pkgreport.cgi?package=grep⟩ are avail‐
       able.
   Known Bugs
       Large repetition counts in the {n,m} construct may cause grep to use lots of memory.  In addition, certain other obscure regular expressions require exponential time and space, and may cause grep to run out of memory.
       Back-references are very slow, and may require exponential time.
EXAMPLE
       The following example outputs the location and contents of any line containing “f” and ending in “.c”, within all files in the current directory whose names contain “g” and end in “.h”.  The -n option outputs line numbers,
       the -- argument treats expansions of “*g*.h” starting with “-” as file names not options, and the empty file /dev/null causes file names to be output even if only one file name happens to be of the form “*g*.h”.
         $ grep -n -- 'f.*\.c$' *g*.h /dev/null
         argmatch.h:1:/* definitions and prototypes for argmatch.c
       The only line that matches is line 1 of argmatch.h.  Note that the regular expression syntax used in the pattern differs from the globbing syntax that the shell uses to match file names.
SEE ALSO
   Regular Manual Pages
       awk(1), cmp(1), diff(1), find(1), perl(1), sed(1), sort(1), xargs(1), read(2), pcre(3), pcresyntax(3), pcrepattern(3), terminfo(5), glob(7), regex(7).
   Full Documentation
       A complete manual ⟨https://www.gnu.org/software/grep/manual/⟩ is available.  If the info and grep programs are properly installed at your site, the command
              info grep
       should give you access to the complete manual.
GNU grep 3.4                                                                                                  2019-12-29                                                                                                      GREP(1)

Resources

Wikipedia – grep


How to: Use shortcut keys/Key combinations in Linux Terminal

1 Tab

When entering command, enter beginning of the command, file name or folder name or command option then press “Tab” key, it will complete the rest for you automatically or show all possible results.

2 Ctrl + C

Terminate/Kill the command or process, it will terminate the running process immediately. (signal SIGINT). It can be intercepted by a program, thus the program can clean itself up before exiting or not exit at all.

3 Ctrl + Z

Suspending a process by sending the SIGSTOP signal, it cannot be intercepted by the program.

4 Ctrl + D

Exit the current terminal. If you are using SSH, it will close it. If you are using a terminal directly, it will close the terminal window.

5 Ctrl + L

Clear terminal screen, same effect as “clear” command

6 Ctrl + A

Move the type cursor to the beginning of the line (Same as pressing “Home” key on keyboard)

7 Ctrl + E

Move the type cursor to the end of the line (Same as pressing “End” key on keyboard)

8 Ctrl + U

Wipe the line and move the type cursor to the beginning of the line (Instead of use “Backspace” key to clear the line slowly)

9 Ctrl + K

Wipe the content from the type cursor to the end of the line

10 Ctrl + W

Clear a word

Before Ctrl + W

Before Ctrl + W
Before Ctrl + W

After Ctrl + W

After Ctrl + W
After Ctrl + W

11 Ctrl + Y

It will paste text removed by Ctrl + U, Ctrl + U and Ctrl + K. If you have deleted text by mistake, this will be helpful.

12 Ctrl + P

Review last command, use repetitively to go back further. Many Terminal provides this review function by PageUp key as well. Some provide the review function by using up arrow key as well (↑).

13 Ctrl + N

Similar usage as Ctrl + P but opposite direction, this command navigate to more recent commands. Many Terminal provides this review function by PageDown key as well. Some provide the review function by using down arrow key as well (↓).

14 Ctrl + R

Used for search history commands

Bonus:

Alternatively, we can use “history” command to show all history command

To search from history command, we can use “history | grep searchTerm”


Linux Bash/Shell simple, basic flow control

“if else” and pass variable to the script

if [condition]
 then
     //if block code
 else
     // else block code
 fi
#!/bin/bash
# https://dannyda.com
if [ $1 == $2 ];then
	echo "Numbers are equal ("$1" = "$2")"
elif [ $1 -gt $2 ];then
	echo "1st Number is greater than 2nd Number ("$1" > "$2")"
elif [ $1 -lt $2 ];then
	echo "1st Number is smaller than 2nd Number ("$1" < "$2")"
else
	echo "error"
fi
if else, pass variables to script
if else, pass variables to script

for Loop

for [var] in [list]
do
    //command1
    //command2
done
#!/bin/bash
# https://dannyda.com
for variable in 1 2 3 4 $(echo 7)
do
	echo "The value is: $variable"
done
for i in {1..3}
do
	echo "Loop $i times"
done
echo "2 Done"
echo
for i in {0..10..2}
do 
	echo "Step of 2, $i times"
done
echo "3 Done"
echo
for loop
for loop

while Loop

while [condition]
do
    //command1
    //command2
done
while [condition]; do commands; done
#!/bin/bash
# https://dannyda.com
i=0
while [[ $i<5 ]]
do
    echo $i
    let "i++"
done
echo "Job Done"
echo
i=0
while [[ $i<5 ]]; do echo $1 $((i++)); done
while loop
while loop

while Loop with input (Interactive script)

while read [condition]
do
    //command1
    //command2
done
#!/bin/bash
# https://dannyda.com
echo '<CTRL-D> to exit'
while read input
do
	echo "The number is $input"
done
while with input (interactive script)
while with input (interactive script)

until Loop

Until loop is opposite to while loop, it execute the given commands as long as the given condition evaluates is false

until [condition]
do
    //command1
    //command2
done
#!/bin/bash
# https://dannyda.com
i=0
until [ $i -gt 5 ]
do
  echo Counter: $i
  ((i++))
done
echo "-----------"
i=0
while [ $i -lt 6 ]
do
  echo Counter: $i
  ((i++))
done
until loop
until loop

Infinite while Loop

Use Ctrl + C to stop/exit the loop

while true
do
    //command1
    //command2
done
#!/bin/bash
# https://dannyda.com
while true
do
	echo a
done
infinite while loop
infinite while loop

Infinite for Loop

Use Ctrl + C to stop/exit the loop

for (( ; ; ))
do
    //command1
    //command2
done

infinite for loop
infinite for loop

Options/Case/Switch/Select Case

case  $variable  in
     pattern1)
         command1
         command2
         …
         ….
     ;;
     pattern2)
         command1
         command2
         …
         ….
     ;;
     patternN)
         command1
         command2
         …
         ….
     ;;
     *)
         command1
         command2
         …
         ….
 esac
case  $variable  in
     pattern1|pattern2|pattern3)
         command1
         command2
         …
         ….
     ;;
     pattern4|pattern5|pattern6)
         command1
         command2
         …
         ….
     ;;
     pattern7|pattern8|patternN)
         command1
         command2
         …
         ….
     ;;
     *)
         command1
         command2
         …
         ….
 esac
esacThe EOF for case
)the end of the pattern
*)Else, if doesn’t match anything
;;The end of current case clause
#!/bin/bash
# https://dannyda.com
case $1 in
    a) echo 'Case a'
    ;;
    b) echo 'Case b'
    ;;
    3) echo 'Case 3'
    ;;
    *) echo 'Not Case a or Case b or Case 3'
    ;;
esac
Case
Case

How to: Automatically renew Let’s Encrypt certificate

Table of contents

  1. Official Method
  2. By using Script and Cron Job
  3. Bonus(Get renewal results via email and write to a log file)

1 Official Method

When installing “Certbot”, by default the Certbot packages on the system come with a cron job or systemd timer which will renew certificates for you automatically before they expire. You do not need to run Certbot manually, unless there are some changes to the configuration. By running following command we can test the automatic renewal.

sudo certbot renew --dry-run

The command to renew certificate via certbot is installed in one of the following locations:

/etc/crontab/
/etc/cron./
systemctl list-timers

It will attempts to renew every 12 hours daily.

2 By using Script and Cron Job

It is an old script (But still works) written by Erika Heidi (With light modification)

1 Save the following script to “/opt/letsencrypt/le-renew.sh” or other locations you like. (Remember to use chmod to allow execution of this file) (Double click on the code to select all, the copy)

#!/bin/bash
#================================================================
# Let's Encrypt renewal script for Apache on Ubuntu/Debian
# @author Erika Heidi<[email protected]>
# @Edited by https://dannyda.com
# Usage: ./le-renew.sh [base-domain-name]
# More info: http://do.co/1mbVihI
#================================================================
domain=$1
le_path='/opt/letsencrypt'
le_conf='/etc/letsencrypt'
exp_limit=29;
get_domain_list(){
        certdomain=$1
        config_file="$le_conf/renewal/$certdomain.conf"
        
	if [ ! -f $config_file ] ; then
                echo "[ERROR] The config file for the certificate $certdomain was not found."
                exit 1;
        fi
        domains=$(grep --only-matching --perl-regex "(?<=domains \= ).*" "${config_file}")
        last_char=$(echo "${domains}" | awk '{print substr($0,length,1)}')
        if [ "${last_char}" = "," ]; then
                domains=$(echo "${domains}" |awk '{print substr($0, 1, length-1)}')
        fi
        echo $domains;
}
if [ -z "$domain" ] ; then
        echo "[ERROR] you must provide the domain name for the certificate renewal."
        exit 1;
fi
cert_file="/etc/letsencrypt/live/$domain/fullchain.pem"
if [ ! -f $cert_file ]; then
	echo "[ERROR] certificate file not found for domain $domain."
	exit 1;
fi
exp=$(date -d "`openssl x509 -in $cert_file -text -noout|grep "Not After"|cut -c 25-`" +%s)
datenow=$(date -d "now" +%s)
days_exp=$(echo \( $exp - $datenow \) / 86400 |bc)
echo "Checking expiration date for $domain..."
if [ "$days_exp" -gt "$exp_limit" ] ; then
	echo "The certificate is up to date, no need for renewal ($days_exp days left)."
	exit 0;
else
	echo "The certificate for $domain is about to expire soon. Starting renewal request..."
	domain_list=$( get_domain_list $domain )
	###Original line###"$le_path"/letsencrypt-auto certonly --apache --renew-by-default --domains "${domain_list}"
	"$le_path"/letsencrypt-auto renew
	echo "Restarting Apache..."
	###Original line###/usr/sbin/service apache2 reload
	systemctl restart apache2
	echo "Renewal process finished for domain $domain"
	exit 0;
fi

2 Save following script to “/opt/letsencrypt/letsencrypt-auto” or other locations you like. (Remember to use chmod to allow execution of this file) (Double click on the code to select all, the copy)

#!/bin/sh
#
# Download and run the latest release version of the Certbot client.
#
# NOTE: THIS SCRIPT IS AUTO-GENERATED AND SELF-UPDATING
#
# IF YOU WANT TO EDIT IT LOCALLY, *ALWAYS* RUN YOUR COPY WITH THE
# "--no-self-upgrade" FLAG
#
# IF YOU WANT TO SEND PULL REQUESTS, THE REAL SOURCE FOR THIS FILE IS
# letsencrypt-auto-source/letsencrypt-auto.template AND
# letsencrypt-auto-source/pieces/bootstrappers/*
set -e  # Work even if somebody does "sh thisscript.sh".
# Note: you can set XDG_DATA_HOME or VENV_PATH before running this script,
# if you want to change where the virtual environment will be installed
# HOME might not be defined when being run through something like systemd
if [ -z "$HOME" ]; then
  HOME=~root
fi
if [ -z "$XDG_DATA_HOME" ]; then
  XDG_DATA_HOME=~/.local/share
fi
if [ -z "$VENV_PATH" ]; then
  # We export these values so they are preserved properly if this script is
  # rerun with sudo/su where $HOME/$XDG_DATA_HOME may have a different value.
  export OLD_VENV_PATH="$XDG_DATA_HOME/letsencrypt"
  export VENV_PATH="/opt/eff.org/certbot/venv"
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="1.0.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
to both this script and certbot will be downloaded and installed. After
ensuring you have the latest versions installed, certbot will be invoked with
all arguments you have provided.
Help for certbot itself cannot be provided until it is installed.
  --debug                                   attempt experimental installation
  -h, --help                                print this help
  -n, --non-interactive, --noninteractive   run without asking for user input
  --no-bootstrap                            do not install OS dependencies
  --no-permissions-check                    do not warn about file system permissions
  --no-self-upgrade                         do not download updates
  --os-packages-only                        install OS dependencies and exit
  --install-only                            install certbot, upgrade if needed, and exit
  -v, --verbose                             provide more output
  -q, --quiet                               provide only update/error output;
                                            implies --non-interactive
All arguments are accepted and forwarded to the Certbot client when run."
export CERTBOT_AUTO="$0"
for arg in "[email protected]" ; do
  case "$arg" in
    --debug)
      DEBUG=1;;
    --os-packages-only)
      OS_PACKAGES_ONLY=1;;
    --install-only)
      INSTALL_ONLY=1;;
    --no-self-upgrade)
      # Do not upgrade this script (also prevents client upgrades, because each
      # copy of the script pins a hash of the python client)
      NO_SELF_UPGRADE=1;;
    --no-permissions-check)
      NO_PERMISSIONS_CHECK=1;;
    --no-bootstrap)
      NO_BOOTSTRAP=1;;
    --help)
      HELP=1;;
    --noninteractive|--non-interactive)
      NONINTERACTIVE=1;;
    --quiet)
      QUIET=1;;
    renew)
      ASSUME_YES=1;;
    --verbose)
      VERBOSE=1;;
    -[!-]*)
      OPTIND=1
      while getopts ":hnvq" short_arg $arg; do
        case "$short_arg" in
          h)
            HELP=1;;
          n)
            NONINTERACTIVE=1;;
          q)
            QUIET=1;;
          v)
            VERBOSE=1;;
        esac
      done;;
  esac
done
if [ $BASENAME = "letsencrypt-auto" ]; then
  # letsencrypt-auto does not respect --help or --yes for backwards compatibility
  NONINTERACTIVE=1
  HELP=0
fi
# Set ASSUME_YES to 1 if QUIET or NONINTERACTIVE
if [ "$QUIET" = 1 -o "$NONINTERACTIVE" = 1 ]; then
  ASSUME_YES=1
fi
say() {
    if [  "$QUIET" != 1 ]; then
        echo "[email protected]"
    fi
}
error() {
    echo "[email protected]"
}
# Support for busybox and others where there is no "command",
# but "which" instead
if command -v command > /dev/null 2>&amp;1 ; then
  export EXISTS="command -v"
elif which which > /dev/null 2>&amp;1 ; then
  export EXISTS="which"
else
  error "Cannot find command nor which... please install one!"
  exit 1
fi
# Certbot itself needs root access for almost all modes of operation.
# certbot-auto needs root access to bootstrap OS dependencies and install
# Certbot at a protected path so it can be safely run as root. To accomplish
# this, this script will attempt to run itself as root if it doesn't have the
# necessary privileges by using `sudo` or falling back to `su` if it is not
# available. The mechanism used to obtain root access can be set explicitly by
# setting the environment variable LE_AUTO_SUDO to 'sudo', 'su', 'su_sudo',
# 'SuSudo', or '' as used below.
# Because the parameters in `su -c` has to be a string,
# we need to properly escape it.
SuSudo() {
  args=""
  # This `while` loop iterates over all parameters given to this function.
  # For each parameter, all `'` will be replace by `'"'"'`, and the escaped string
  # will be wrapped in a pair of `'`, then appended to `$args` string
  # For example, `echo "It's only 1\$\!"` will be escaped to:
  #   'echo' 'It'"'"'s only 1$!'
  #     │       │└┼┘│
  #     │       │ │ └── `'s only 1$!'` the literal string
  #     │       │ └── `\"'\"` is a single quote (as a string)
  #     │       └── `'It'`, to be concatenated with the strings following it
  #     └── `echo` wrapped in a pair of `'`, it's totally fine for the shell command itself
  while [ $# -ne 0 ]; do
    args="$args'$(printf "%s" "$1" | sed -e "s/'/'\"'\"'/g")' "
    shift
  done
  su root -c "$args"
}
# Sets the environment variable SUDO to be the name of the program or function
# to call to get root access. If this script already has root privleges, SUDO
# is set to an empty string. The value in SUDO should be run with the command
# to called with root privileges as arguments.
SetRootAuthMechanism() {
  SUDO=""
  if [ -n "${LE_AUTO_SUDO+x}" ]; then
    case "$LE_AUTO_SUDO" in
      SuSudo|su_sudo|su)
        SUDO=SuSudo
        ;;
      sudo)
        SUDO="sudo -E"
        ;;
      '')
        # If we're not running with root, don't check that this script can only
        # be modified by system users and groups.
        NO_PERMISSIONS_CHECK=1
        ;;
      *)
        error "Error: unknown root authorization mechanism '$LE_AUTO_SUDO'."
        exit 1
    esac
    say "Using preset root authorization mechanism '$LE_AUTO_SUDO'."
  else
    if test "`id -u`" -ne "0" ; then
      if $EXISTS sudo 1>/dev/null 2>&1; then
        SUDO="sudo -E"
      else
        say \"sudo\" is not available, will use \"su\" for installation steps...
        SUDO=SuSudo
      fi
    fi
  fi
}
if [ "$1" = "--cb-auto-has-root" ]; then
  shift 1
else
  SetRootAuthMechanism
  if [ -n "$SUDO" ]; then
    say "Requesting to rerun $0 with root privileges..."
    $SUDO "$0" --cb-auto-has-root "[email protected]"
    exit 0
  fi
fi
# Runs this script again with the given arguments. --cb-auto-has-root is added
# to the command line arguments to ensure we don't try to acquire root a
# second time. After the script is rerun, we exit the current script.
RerunWithArgs() {
    "$0" --cb-auto-has-root "[email protected]"
    exit 0
}
BootstrapMessage() {
  # Arguments: Platform name
  say "Bootstrapping dependencies for $1... (you can skip this with --no-bootstrap)"
}
ExperimentalBootstrap() {
  # Arguments: Platform name, bootstrap function name
  if [ "$DEBUG" = 1 ]; then
    if [ "$2" != "" ]; then
      BootstrapMessage $1
      $2
    fi
  else
    error "FATAL: $1 support is very experimental at present..."
    error "if you would like to work on improving it, please ensure you have backups"
    error "and then run this script again with the --debug flag!"
    error "Alternatively, you can install OS dependencies yourself and run this script"
    error "again with --no-bootstrap."
    exit 1
  fi
}
DeprecationBootstrap() {
  # Arguments: Platform name, bootstrap function name
  if [ "$DEBUG" = 1 ]; then
    if [ "$2" != "" ]; then
      BootstrapMessage $1
      $2
    fi
  else
    error "WARNING: certbot-auto support for this $1 is DEPRECATED!"
    error "Please visit certbot.eff.org to learn how to download a version of"
    error "Certbot that is packaged for your system. While an existing version"
    error "of certbot-auto may work currently, we have stopped supporting updating"
    error "system packages for your system. Please switch to a packaged version"
    error "as soon as possible."
    exit 1
  fi
}
MIN_PYTHON_VERSION="2.7"
MIN_PYVER=$(echo "$MIN_PYTHON_VERSION" | sed 's/\.//')
# Sets LE_PYTHON to Python version string and PYVER to the first two
# digits of the python version
DeterminePythonVersion() {
  # Arguments: "NOCRASH" if we shouldn't crash if we don't find a good python
  #
  # If no Python is found, PYVER is set to 0.
  if [ "$USE_PYTHON_3" = 1 ]; then
    for LE_PYTHON in "$LE_PYTHON" python3; do
      # Break (while keeping the LE_PYTHON value) if found.
      $EXISTS "$LE_PYTHON" > /dev/null &amp;&amp; break
    done
  else
    for LE_PYTHON in "$LE_PYTHON" python2.7 python27 python2 python; do
      # Break (while keeping the LE_PYTHON value) if found.
      $EXISTS "$LE_PYTHON" > /dev/null &amp;&amp; break
    done
  fi
  if [ "$?" != "0" ]; then
    if [ "$1" != "NOCRASH" ]; then
      error "Cannot find any Pythons; please install one!"
      exit 1
    else
      PYVER=0
      return 0
    fi
  fi
  PYVER=`"$LE_PYTHON" -V 2>&amp;1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'`
  if [ "$PYVER" -lt "$MIN_PYVER" ]; then
    if [ "$1" != "NOCRASH" ]; then
      error "You have an ancient version of Python entombed in your operating system..."
      error "This isn't going to work; you'll need at least version $MIN_PYTHON_VERSION."
      exit 1
    fi
  fi
}
# If new packages are installed by BootstrapDebCommon below, this version
# number must be increased.
BOOTSTRAP_DEB_COMMON_VERSION=1
BootstrapDebCommon() {
  # Current version tested with:
  #
  # - Ubuntu
  #     - 14.04 (x64)
  #     - 15.04 (x64)
  # - Debian
  #     - 7.9 "wheezy" (x64)
  #     - sid (2015-10-21) (x64)
  # Past versions tested with:
  #
  # - Debian 8.0 "jessie" (x64)
  # - Raspbian 7.8 (armhf)
  # Believed not to work:
  #
  # - Debian 6.0.10 "squeeze" (x64)
  if [ "$QUIET" = 1 ]; then
    QUIET_FLAG='-qq'
  fi
  apt-get $QUIET_FLAG update || error apt-get update hit problems but continuing anyway...
  # virtualenv binary can be found in different packages depending on
  # distro version (#346)
  virtualenv=
  # virtual env is known to apt and is installable
  if apt-cache show virtualenv > /dev/null 2>&amp;1 ; then
    if ! LC_ALL=C apt-cache --quiet=0 show virtualenv 2>&amp;1 | grep -q 'No packages found'; then
      virtualenv="virtualenv"
    fi
  fi
  if apt-cache show python-virtualenv > /dev/null 2>&1; then
    virtualenv="$virtualenv python-virtualenv"
  fi
  augeas_pkg="libaugeas0 augeas-lenses"
  if [ "$ASSUME_YES" = 1 ]; then
    YES_FLAG="-y"
  fi
  apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
    python \
    python-dev \
    $virtualenv \
    gcc \
    $augeas_pkg \
    libssl-dev \
    openssl \
    libffi-dev \
    ca-certificates \
  if ! $EXISTS virtualenv > /dev/null ; then
    error Failed to install a working \"virtualenv\" command, exiting
    exit 1
  fi
}
# If new packages are installed by BootstrapRpmCommonBase below, version
# numbers in rpm_common.sh and rpm_python3.sh must be increased.
# Sets TOOL to the name of the package manager
# Sets appropriate values for YES_FLAG and QUIET_FLAG based on $ASSUME_YES and $QUIET_FLAG.
# Enables EPEL if applicable and possible.
InitializeRPMCommonBase() {
  if type dnf 2>/dev/null
  then
    TOOL=dnf
  elif type yum 2>/dev/null
  then
    TOOL=yum
  else
    error "Neither yum nor dnf found. Aborting bootstrap!"
    exit 1
  fi
  if [ "$ASSUME_YES" = 1 ]; then
    YES_FLAG="-y"
  fi
  if [ "$QUIET" = 1 ]; then
    QUIET_FLAG='--quiet'
  fi
  if ! $TOOL list *virtualenv >/dev/null 2>&1; then
    echo "To use Certbot, packages from the EPEL repository need to be installed."
    if ! $TOOL list epel-release >/dev/null 2>&1; then
      error "Enable the EPEL repository and try running Certbot again."
      exit 1
    fi
    if [ "$ASSUME_YES" = 1 ]; then
      /bin/echo -n "Enabling the EPEL repository in 3 seconds..."
      sleep 1s
      /bin/echo -ne "\e[0K\rEnabling the EPEL repository in 2 seconds..."
      sleep 1s
      /bin/echo -e "\e[0K\rEnabling the EPEL repository in 1 second..."
      sleep 1s
    fi
    if ! $TOOL install $YES_FLAG $QUIET_FLAG epel-release; then
      error "Could not enable EPEL. Aborting bootstrap!"
      exit 1
    fi
  fi
}
BootstrapRpmCommonBase() {
  # Arguments: whitespace-delimited python packages to install
  InitializeRPMCommonBase # This call is superfluous in practice
  pkgs="
    gcc
    augeas-libs
    openssl
    openssl-devel
    libffi-devel
    redhat-rpm-config
    ca-certificates
  "
  # Add the python packages
  pkgs="$pkgs
    $1
  "
  if $TOOL list installed "httpd" >/dev/null 2>&1; then
    pkgs="$pkgs
      mod_ssl
    "
  fi
  if ! $TOOL install $YES_FLAG $QUIET_FLAG $pkgs; then
    error "Could not install OS dependencies. Aborting bootstrap!"
    exit 1
  fi
}
# If new packages are installed by BootstrapRpmCommon below, this version
# number must be increased.
BOOTSTRAP_RPM_COMMON_VERSION=1
BootstrapRpmCommon() {
  # Tested with:
  #   - Fedora 20, 21, 22, 23 (x64)
  #   - Centos 7 (x64: on DigitalOcean droplet)
  #   - CentOS 7 Minimal install in a Hyper-V VM
  #   - CentOS 6
  InitializeRPMCommonBase
  # Most RPM distros use the "python" or "python-" naming convention.  Let's try that first.
  if $TOOL list python >/dev/null 2>&1; then
    python_pkgs="$python
      python-devel
      python-virtualenv
      python-tools
      python-pip
    "
  # Fedora 26 starts to use the prefix python2 for python2 based packages.
  # this elseif is theoretically for any Fedora over version 26:
  elif $TOOL list python2 >/dev/null 2>&1; then
    python_pkgs="$python2
      python2-libs
      python2-setuptools
      python2-devel
      python2-virtualenv
      python2-tools
      python2-pip
    "
  # Some distros and older versions of current distros use a "python27"
  # instead of the "python" or "python-" naming convention.
  else
    python_pkgs="$python27
      python27-devel
      python27-virtualenv
      python27-tools
      python27-pip
    "
  fi
  BootstrapRpmCommonBase "$python_pkgs"
}
# If new packages are installed by BootstrapRpmPython3 below, this version
# number must be increased.
BOOTSTRAP_RPM_PYTHON3_VERSION=1
BootstrapRpmPython3() {
  # Tested with:
  #   - CentOS 6
  #   - Fedora 29
  InitializeRPMCommonBase
  # Fedora 29 must use python3-virtualenv
  if $TOOL list python3-virtualenv >/dev/null 2>&1; then
    python_pkgs="python3
      python3-virtualenv
      python3-devel
    "
  # EPEL uses python34
  elif $TOOL list python34 >/dev/null 2>&1; then
    python_pkgs="python34
      python34-devel
      python34-tools
    "
  else
    error "No supported Python package available to install. Aborting bootstrap!"
    exit 1
  fi
  BootstrapRpmCommonBase "$python_pkgs"
}
# If new packages are installed by BootstrapSuseCommon below, this version
# number must be increased.
BOOTSTRAP_SUSE_COMMON_VERSION=1
BootstrapSuseCommon() {
  # SLE12 don't have python-virtualenv
  if [ "$ASSUME_YES" = 1 ]; then
    zypper_flags="-nq"
    install_flags="-l"
  fi
  if [ "$QUIET" = 1 ]; then
    QUIET_FLAG='-qq'
  fi
  if zypper search -x python-virtualenv >/dev/null 2>&1; then
    OPENSUSE_VIRTUALENV_PACKAGES="python-virtualenv"
  else
    # Since Leap 15.0 (and associated Tumbleweed version), python-virtualenv
    # is a source package, and python2-virtualenv must be used instead.
    # Also currently python2-setuptools is not a dependency of python2-virtualenv,
    # while it should be. Installing it explicitly until upstream fix.
    OPENSUSE_VIRTUALENV_PACKAGES="python2-virtualenv python2-setuptools"
  fi
  zypper $QUIET_FLAG $zypper_flags in $install_flags \
    python \
    python-devel \
    $OPENSUSE_VIRTUALENV_PACKAGES \
    gcc \
    augeas-lenses \
    libopenssl-devel \
    libffi-devel \
    ca-certificates
}
# If new packages are installed by BootstrapArchCommon below, this version
# number must be increased.
BOOTSTRAP_ARCH_COMMON_VERSION=1
BootstrapArchCommon() {
  # Tested with:
  #   - ArchLinux (x86_64)
  #
  # "python-virtualenv" is Python3, but "python2-virtualenv" provides
  # only "virtualenv2" binary, not "virtualenv".
  deps="
    python2
    python-virtualenv
    gcc
    augeas
    openssl
    libffi
    ca-certificates
    pkg-config
  "
  # pacman -T exits with 127 if there are missing dependencies
  missing=$(pacman -T $deps) || true
  if [ "$ASSUME_YES" = 1 ]; then
    noconfirm="--noconfirm"
  fi
  if [ "$missing" ]; then
    if [ "$QUIET" = 1 ]; then
      pacman -S --needed $missing $noconfirm > /dev/null
    else
      pacman -S --needed $missing $noconfirm
    fi
  fi
}
# If new packages are installed by BootstrapGentooCommon below, this version
# number must be increased.
BOOTSTRAP_GENTOO_COMMON_VERSION=1
BootstrapGentooCommon() {
  PACKAGES="
    dev-lang/python:2.7
    dev-python/virtualenv
    app-admin/augeas
    dev-libs/openssl
    dev-libs/libffi
    app-misc/ca-certificates
    virtual/pkgconfig"
  ASK_OPTION="--ask"
  if [ "$ASSUME_YES" = 1 ]; then
    ASK_OPTION=""
  fi
  case "$PACKAGE_MANAGER" in
    (paludis)
      cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
      ;;
    (pkgcore)
      pmerge --noreplace --oneshot $ASK_OPTION $PACKAGES
      ;;
    (portage|*)
      emerge --noreplace --oneshot $ASK_OPTION $PACKAGES
      ;;
  esac
}
# If new packages are installed by BootstrapFreeBsd below, this version number
# must be increased.
BOOTSTRAP_FREEBSD_VERSION=1
BootstrapFreeBsd() {
  if [ "$QUIET" = 1 ]; then
    QUIET_FLAG="--quiet"
  fi
  pkg install -Ay $QUIET_FLAG \
    python \
    py27-virtualenv \
    augeas \
    libffi
}
# If new packages are installed by BootstrapMac below, this version number must
# be increased.
BOOTSTRAP_MAC_VERSION=1
BootstrapMac() {
  if hash brew 2>/dev/null; then
    say "Using Homebrew to install dependencies..."
    pkgman=brew
    pkgcmd="brew install"
  elif hash port 2>/dev/null; then
    say "Using MacPorts to install dependencies..."
    pkgman=port
    pkgcmd="port install"
  else
    say "No Homebrew/MacPorts; installing Homebrew..."
    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    pkgman=brew
    pkgcmd="brew install"
  fi
  $pkgcmd augeas
  if [ "$(which python)" = "/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python" \
      -o "$(which python)" = "/usr/bin/python" ]; then
    # We want to avoid using the system Python because it requires root to use pip.
    # python.org, MacPorts or HomeBrew Python installations should all be OK.
    say "Installing python..."
    $pkgcmd python
  fi
  # Workaround for _dlopen not finding augeas on macOS
  if [ "$pkgman" = "port" ] &amp;&amp; ! [ -e "/usr/local/lib/libaugeas.dylib" ] &amp;&amp; [ -e "/opt/local/lib/libaugeas.dylib" ]; then
    say "Applying augeas workaround"
    mkdir -p /usr/local/lib/
    ln -s /opt/local/lib/libaugeas.dylib /usr/local/lib/
  fi
  if ! hash pip 2>/dev/null; then
    say "pip not installed"
    say "Installing pip..."
    curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | python
  fi
  if ! hash virtualenv 2>/dev/null; then
    say "virtualenv not installed."
    say "Installing with pip..."
    pip install virtualenv
  fi
}
# If new packages are installed by BootstrapSmartOS below, this version number
# must be increased.
BOOTSTRAP_SMARTOS_VERSION=1
BootstrapSmartOS() {
  pkgin update
  pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv'
}
# If new packages are installed by BootstrapMageiaCommon below, this version
# number must be increased.
BOOTSTRAP_MAGEIA_COMMON_VERSION=1
BootstrapMageiaCommon() {
  if [ "$QUIET" = 1 ]; then
    QUIET_FLAG='--quiet'
  fi
  if ! urpmi --force $QUIET_FLAG \
      python \
      libpython-devel \
      python-virtualenv
    then
      error "Could not install Python dependencies. Aborting bootstrap!"
      exit 1
  fi
  if ! urpmi --force $QUIET_FLAG \
      git \
      gcc \
      python-augeas \
      libopenssl-devel \
      libffi-devel \
      rootcerts
    then
      error "Could not install additional dependencies. Aborting bootstrap!"
      exit 1
    fi
}
# Set Bootstrap to the function that installs OS dependencies on this system
# and BOOTSTRAP_VERSION to the unique identifier for the current version of
# that function. If Bootstrap is set to a function that doesn't install any
# packages BOOTSTRAP_VERSION is not set.
if [ -f /etc/debian_version ]; then
  Bootstrap() {
    BootstrapMessage "Debian-based OSes"
    BootstrapDebCommon
  }
  BOOTSTRAP_VERSION="BootstrapDebCommon $BOOTSTRAP_DEB_COMMON_VERSION"
elif [ -f /etc/mageia-release ]; then
  # Mageia has both /etc/mageia-release and /etc/redhat-release
  Bootstrap() {
    ExperimentalBootstrap "Mageia" BootstrapMageiaCommon
  }
  BOOTSTRAP_VERSION="BootstrapMageiaCommon $BOOTSTRAP_MAGEIA_COMMON_VERSION"
elif [ -f /etc/redhat-release ]; then
  # Run DeterminePythonVersion to decide on the basis of available Python versions
  # whether to use 2.x or 3.x on RedHat-like systems.
  # Then, revert LE_PYTHON to its previous state.
  prev_le_python="$LE_PYTHON"
  unset LE_PYTHON
  DeterminePythonVersion "NOCRASH"
  RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null &amp;&amp; echo $ID) || echo "unknown"`
  # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
  # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
  # error, RPM_DIST_VERSION is set to "unknown".
  RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null &amp;&amp; echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
  # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
  # characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
  if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
     RPM_DIST_VERSION=0
  fi
  # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
  # RHEL 8 also uses python3 by default.
  if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
    RPM_USE_PYTHON_3=1
  elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
    RPM_USE_PYTHON_3=1
  elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then
    RPM_USE_PYTHON_3=1
  else
    RPM_USE_PYTHON_3=0
  fi
  if [ "$RPM_USE_PYTHON_3" = 1 ]; then
    Bootstrap() {
      BootstrapMessage "RedHat-based OSes that will use Python3"
      BootstrapRpmPython3
    }
    USE_PYTHON_3=1
    BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION"
  else
    Bootstrap() {
      BootstrapMessage "RedHat-based OSes"
      BootstrapRpmCommon
    }
    BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
  fi
  LE_PYTHON="$prev_le_python"
elif [ -f /etc/os-release ] &amp;&amp; `grep -q openSUSE /etc/os-release` ; then
  Bootstrap() {
    BootstrapMessage "openSUSE-based OSes"
    BootstrapSuseCommon
  }
  BOOTSTRAP_VERSION="BootstrapSuseCommon $BOOTSTRAP_SUSE_COMMON_VERSION"
elif [ -f /etc/arch-release ]; then
  Bootstrap() {
    if [ "$DEBUG" = 1 ]; then
      BootstrapMessage "Archlinux"
      BootstrapArchCommon
    else
      error "Please use pacman to install letsencrypt packages:"
      error "# pacman -S certbot certbot-apache"
      error
      error "If you would like to use the virtualenv way, please run the script again with the"
      error "--debug flag."
      exit 1
    fi
  }
  BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
elif [ -f /etc/manjaro-release ]; then
  Bootstrap() {
    ExperimentalBootstrap "Manjaro Linux" BootstrapArchCommon
  }
  BOOTSTRAP_VERSION="BootstrapArchCommon $BOOTSTRAP_ARCH_COMMON_VERSION"
elif [ -f /etc/gentoo-release ]; then
  Bootstrap() {
    DeprecationBootstrap "Gentoo" BootstrapGentooCommon
  }
  BOOTSTRAP_VERSION="BootstrapGentooCommon $BOOTSTRAP_GENTOO_COMMON_VERSION"
elif uname | grep -iq FreeBSD ; then
  Bootstrap() {
    DeprecationBootstrap "FreeBSD" BootstrapFreeBsd
  }
  BOOTSTRAP_VERSION="BootstrapFreeBsd $BOOTSTRAP_FREEBSD_VERSION"
elif uname | grep -iq Darwin ; then
  Bootstrap() {
    DeprecationBootstrap "macOS" BootstrapMac
  }
  BOOTSTRAP_VERSION="BootstrapMac $BOOTSTRAP_MAC_VERSION"
elif [ -f /etc/issue ] &amp;&amp; grep -iq "Amazon Linux" /etc/issue ; then
  Bootstrap() {
    ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon
  }
  BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
elif [ -f /etc/product ] &amp;&amp; grep -q "Joyent Instance" /etc/product ; then
  Bootstrap() {
    ExperimentalBootstrap "Joyent SmartOS Zone" BootstrapSmartOS
  }
  BOOTSTRAP_VERSION="BootstrapSmartOS $BOOTSTRAP_SMARTOS_VERSION"
else
  Bootstrap() {
    error "Sorry, I don't know how to bootstrap Certbot on your operating system!"
    error
    error "You will need to install OS dependencies, configure virtualenv, and run pip install manually."
    error "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites"
    error "for more info."
    exit 1
  }
fi
# We handle this case after determining the normal bootstrap version to allow
# variables like USE_PYTHON_3 to be properly set. As described above, if the
# Bootstrap function doesn't install any packages, BOOTSTRAP_VERSION should not
# be set so we unset it here.
if [ "$NO_BOOTSTRAP" = 1 ]; then
  Bootstrap() {
    :
  }
  unset BOOTSTRAP_VERSION
fi
# Sets PREV_BOOTSTRAP_VERSION to the identifier for the bootstrap script used
# to install OS dependencies on this system. PREV_BOOTSTRAP_VERSION isn't set
# if it is unknown how OS dependencies were installed on this system.
SetPrevBootstrapVersion() {
  if [ -f $BOOTSTRAP_VERSION_PATH ]; then
    PREV_BOOTSTRAP_VERSION=$(cat "$BOOTSTRAP_VERSION_PATH")
  # The list below only contains bootstrap version strings that existed before
  # we started writing them to disk.
  #
  # DO NOT MODIFY THIS LIST UNLESS YOU KNOW WHAT YOU'RE DOING!
  elif grep -Fqx "$BOOTSTRAP_VERSION" << "UNLIKELY_EOF"
BootstrapDebCommon 1
BootstrapMageiaCommon 1
BootstrapRpmCommon 1
BootstrapSuseCommon 1
BootstrapArchCommon 1
BootstrapGentooCommon 1
BootstrapFreeBsd 1
BootstrapMac 1
BootstrapSmartOS 1
UNLIKELY_EOF
  then
    # If there's no bootstrap version saved to disk, but the currently selected
    # bootstrap script is from before we started saving the version number,
    # return the currently selected version to prevent us from rebootstrapping
    # unnecessarily.
    PREV_BOOTSTRAP_VERSION="$BOOTSTRAP_VERSION"
  fi
}
TempDir() {
  mktemp -d 2>/dev/null || mktemp -d -t 'le'  # Linux || macOS
}
# Returns 0 if a letsencrypt installation exists at $OLD_VENV_PATH, otherwise,
# returns a non-zero number.
OldVenvExists() {
    [ -n "$OLD_VENV_PATH" -a -f "$OLD_VENV_PATH/bin/letsencrypt" ]
}
# Given python path, version 1 and version 2, check if version 1 is outdated compared to version 2.
# An unofficial version provided as version 1 (eg. 0.28.0.dev0) will be treated
# specifically by printing "UNOFFICIAL". Otherwise, print "OUTDATED" if version 1
# is outdated, and "UP_TO_DATE" if not.
# This function relies only on installed python environment (2.x or 3.x) by certbot-auto.
CompareVersions() {
    "$1" - "$2" "$3" << "UNLIKELY_EOF"
import sys
from distutils.version import StrictVersion
try:
    current = StrictVersion(sys.argv[1])
except ValueError:
    sys.stdout.write('UNOFFICIAL')
    sys.exit()
try:
    remote = StrictVersion(sys.argv[2])
except ValueError:
    sys.stdout.write('UP_TO_DATE')
    sys.exit()
if current < remote:
    sys.stdout.write('OUTDATED')
else:
    sys.stdout.write('UP_TO_DATE')
UNLIKELY_EOF
}
# Create a new virtual environment for Certbot. It will overwrite any existing one.
# Parameters: LE_PYTHON, VENV_PATH, PYVER, VERBOSE
CreateVenv() {
    "$1" - "$2" "$3" "$4" << "UNLIKELY_EOF"
#!/usr/bin/env python
import os
import shutil
import subprocess
import sys
def create_venv(venv_path, pyver, verbose):
    if os.path.exists(venv_path):
        shutil.rmtree(venv_path)
    stdout = sys.stdout if verbose == '1' else open(os.devnull, 'w')
    if int(pyver) <= 27:
        # Use virtualenv binary
        environ = os.environ.copy()
        environ['VIRTUALENV_NO_DOWNLOAD'] = '1'
        command = ['virtualenv', '--no-site-packages', '--python', sys.executable, venv_path]
        subprocess.check_call(command, stdout=stdout, env=environ)
    else:
        # Use embedded venv module in Python 3
        command = [sys.executable, '-m', 'venv', venv_path]
        subprocess.check_call(command, stdout=stdout)
if __name__ == '__main__':
    create_venv(*sys.argv[1:])
UNLIKELY_EOF
}
# Check that the given PATH_TO_CHECK has secured permissions.
# Parameters: LE_PYTHON, PATH_TO_CHECK
CheckPathPermissions() {
    "$1" - "$2" << "UNLIKELY_EOF"
"""Verifies certbot-auto cannot be modified by unprivileged users.
This script takes the path to certbot-auto as its only command line
argument.  It then checks that the file can only be modified by uid/gid
< 1000 and if other users can modify the file, it prints a warning with
a suggestion on how to solve the problem.
Permissions on symlinks in the absolute path of certbot-auto are ignored
and only the canonical path to certbot-auto is checked. There could be
permissions problems due to the symlinks that are unreported by this
script, however, issues like this were not caused by our documentation
and are ignored for the sake of simplicity.
All warnings are printed to stdout rather than stderr so all stderr
output from this script can be suppressed to avoid printing messages if
this script fails for some reason.
"""
from __future__ import print_function
import os
import stat
import sys
FORUM_POST_URL = 'https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/'
def has_safe_permissions(path):
    """Returns True if the given path has secure permissions.
    The permissions are considered safe if the file is only writable by
    uid/gid < 1000.
    The reason we allow more IDs than 0 is because on some systems such
    as Debian, system users/groups other than uid/gid 0 are used for the
    path we recommend in our instructions which is /usr/local/bin.  1000
    was chosen because on Debian 0-999 is reserved for system IDs[1] and
    on RHEL either 0-499 or 0-999 is reserved depending on the
    version[2][3]. Due to these differences across different OSes, this
    detection isn't perfect so we only determine permissions are
    insecure when we can be reasonably confident there is a problem
    regardless of the underlying OS.
    [1] https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes
    [2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-managing_users_and_groups
    [3] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-managing_users_and_groups
    :param str path: filesystem path to check
    :returns: True if the path has secure permissions, otherwise, False
    :rtype: bool
    """
    # os.stat follows symlinks before obtaining information about a file.
    stat_result = os.stat(path)
    if stat_result.st_mode &amp; stat.S_IWOTH:
        return False
    if stat_result.st_mode &amp; stat.S_IWGRP and stat_result.st_gid >= 1000:
        return False
    if stat_result.st_mode &amp; stat.S_IWUSR and stat_result.st_uid >= 1000:
        return False
    return True
def main(certbot_auto_path):
    current_path = os.path.realpath(certbot_auto_path)
    last_path = None
    permissions_ok = True
    # This loop makes use of the fact that os.path.dirname('/') == '/'.
    while current_path != last_path and permissions_ok:
        permissions_ok = has_safe_permissions(current_path)
        last_path = current_path
        current_path = os.path.dirname(current_path)
    if not permissions_ok:
        print('{0} has insecure permissions!'.format(certbot_auto_path))
        print('To learn how to fix them, visit {0}'.format(FORUM_POST_URL))
if __name__ == '__main__':
    main(sys.argv[1])
UNLIKELY_EOF
}
if [ "$1" = "--le-auto-phase2" ]; then
  # Phase 2: Create venv, install LE, and run.
  shift 1  # the --le-auto-phase2 arg
  SetPrevBootstrapVersion
  if [ -z "$PHASE_1_VERSION" -a "$USE_PYTHON_3" = 1 ]; then
    unset LE_PYTHON
  fi
  INSTALLED_VERSION="none"
  if [ -d "$VENV_PATH" ] || OldVenvExists; then
    # If the selected Bootstrap function isn't a noop and it differs from the
    # previously used version
    if [ -n "$BOOTSTRAP_VERSION" -a "$BOOTSTRAP_VERSION" != "$PREV_BOOTSTRAP_VERSION" ]; then
      # if non-interactive mode or stdin and stdout are connected to a terminal
      if [ \( "$NONINTERACTIVE" = 1 \) -o \( \( -t 0 \) -a \( -t 1 \) \) ]; then
        if [ -d "$VENV_PATH" ]; then
          rm -rf "$VENV_PATH"
        fi
        # In the case the old venv was just a symlink to the new one,
        # OldVenvExists is now false because we deleted the venv at VENV_PATH.
        if OldVenvExists; then
          rm -rf "$OLD_VENV_PATH"
          ln -s "$VENV_PATH" "$OLD_VENV_PATH"
        fi
        RerunWithArgs "[email protected]"
      else
        error "Skipping upgrade because new OS dependencies may need to be installed."
        error
        error "To upgrade to a newer version, please run this script again manually so you can"
        error "approve changes or with --non-interactive on the command line to automatically"
        error "install any required packages."
        # Set INSTALLED_VERSION to be the same so we don't update the venv
        INSTALLED_VERSION="$LE_AUTO_VERSION"
        # Continue to use OLD_VENV_PATH if the new venv doesn't exist
        if [ ! -d "$VENV_PATH" ]; then
          VENV_BIN="$OLD_VENV_PATH/bin"
        fi
      fi
    elif [ -f "$VENV_BIN/letsencrypt" ]; then
      # --version output ran through grep due to python-cryptography DeprecationWarnings
      # grep for both certbot and letsencrypt until certbot and shim packages have been released
      INSTALLED_VERSION=$("$VENV_BIN/letsencrypt" --version 2>&amp;1 | grep "^certbot\|^letsencrypt" | cut -d " " -f 2)
      if [ -z "$INSTALLED_VERSION" ]; then
          error "Error: couldn't get currently installed version for $VENV_BIN/letsencrypt: " 1>&amp;2
          "$VENV_BIN/letsencrypt" --version
          exit 1
      fi
    fi
  fi
  if [ "$LE_AUTO_VERSION" != "$INSTALLED_VERSION" ]; then
    say "Creating virtual environment..."
    DeterminePythonVersion
    CreateVenv "$LE_PYTHON" "$VENV_PATH" "$PYVER" "$VERBOSE"
    if [ -n "$BOOTSTRAP_VERSION" ]; then
      echo "$BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
    elif [ -n "$PREV_BOOTSTRAP_VERSION" ]; then
      echo "$PREV_BOOTSTRAP_VERSION" > "$BOOTSTRAP_VERSION_PATH"
    fi
    say "Installing Python packages..."
    TEMP_DIR=$(TempDir)
    trap 'rm -rf "$TEMP_DIR"' EXIT
    # There is no $ interpolation due to quotes on starting heredoc delimiter.
    # -------------------------------------------------------------------------
    cat << "UNLIKELY_EOF" > "$TEMP_DIR/letsencrypt-auto-requirements.txt"
# This is the flattened list of packages certbot-auto installs.
# To generate this, do (with docker and package hashin installed):
# ```
# letsencrypt-auto-source/rebuild_dependencies.py \
#   letsencrypt-auto-source/pieces/dependency-requirements.txt
# ```
# If you want to update a single dependency, run commands similar to these:
# ```
# pip install hashin
# hashin -r dependency-requirements.txt cryptography==1.5.2
# ```
ConfigArgParse==0.14.0 \
    --hash=sha256:2e2efe2be3f90577aca9415e32cb629aa2ecd92078adbe27b53a03e53ff12e91
certifi==2019.9.11 \
    --hash=sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50 \
    --hash=sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef
cffi==1.13.2 \
    --hash=sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42 \
    --hash=sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04 \
    --hash=sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5 \
    --hash=sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54 \
    --hash=sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba \
    --hash=sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57 \
    --hash=sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396 \
    --hash=sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12 \
    --hash=sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97 \
    --hash=sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43 \
    --hash=sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db \
    --hash=sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3 \
    --hash=sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b \
    --hash=sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579 \
    --hash=sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346 \
    --hash=sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159 \
    --hash=sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652 \
    --hash=sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e \
    --hash=sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a \
    --hash=sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506 \
    --hash=sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f \
    --hash=sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d \
    --hash=sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c \
    --hash=sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20 \
    --hash=sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858 \
    --hash=sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc \
    --hash=sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a \
    --hash=sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3 \
    --hash=sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e \
    --hash=sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410 \
    --hash=sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25 \
    --hash=sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b \
    --hash=sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d
chardet==3.0.4 \
    --hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
    --hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
configobj==5.0.6 \
    --hash=sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902
cryptography==2.8 \
    --hash=sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c \
    --hash=sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595 \
    --hash=sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad \
    --hash=sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651 \
    --hash=sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2 \
    --hash=sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff \
    --hash=sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d \
    --hash=sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42 \
    --hash=sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d \
    --hash=sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e \
    --hash=sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912 \
    --hash=sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793 \
    --hash=sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13 \
    --hash=sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7 \
    --hash=sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0 \
    --hash=sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879 \
    --hash=sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f \
    --hash=sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9 \
    --hash=sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2 \
    --hash=sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf \
    --hash=sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8
distro==1.4.0 \
    --hash=sha256:362dde65d846d23baee4b5c058c8586f219b5a54be1cf5fc6ff55c4578392f57 \
    --hash=sha256:eedf82a470ebe7d010f1872c17237c79ab04097948800029994fa458e52fb4b4
enum34==1.1.6 \
    --hash=sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850 \
    --hash=sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a \
    --hash=sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79 \
    --hash=sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1
funcsigs==1.0.2 \
    --hash=sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca \
    --hash=sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50
future==0.18.2 \
    --hash=sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d
idna==2.8 \
    --hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
    --hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
ipaddress==1.0.23 \
    --hash=sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc \
    --hash=sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2
josepy==1.2.0 \
    --hash=sha256:8ea15573203f28653c00f4ac0142520777b1c59d9eddd8da3f256c6ba3cac916 \
    --hash=sha256:9cec9a839fe9520f0420e4f38e7219525daccce4813296627436fe444cd002d3
mock==1.3.0 \
    --hash=sha256:1e247dbecc6ce057299eb7ee019ad68314bb93152e81d9a6110d35f4d5eca0f6 \
    --hash=sha256:3f573a18be94de886d1191f27c168427ef693e8dcfcecf95b170577b2eb69cbb
parsedatetime==2.4 \
    --hash=sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b \
    --hash=sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094
pbr==5.4.3 \
    --hash=sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8 \
    --hash=sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9
pyOpenSSL==19.0.0 \
    --hash=sha256:aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200 \
    --hash=sha256:c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
pyRFC3339==1.1 \
    --hash=sha256:67196cb83b470709c580bb4738b83165e67c6cc60e1f2e4f286cfcb402a926f4 \
    --hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
pycparser==2.19 \
    --hash=sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
pyparsing==2.4.5 \
    --hash=sha256:20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f \
    --hash=sha256:4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a
python-augeas==0.5.0 \
    --hash=sha256:67d59d66cdba8d624e0389b87b2a83a176f21f16a87553b50f5703b23f29bac2
pytz==2019.3 \
    --hash=sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d \
    --hash=sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be
requests==2.21.0 \
    --hash=sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e \
    --hash=sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b
requests-toolbelt==0.9.1 \
    --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \
    --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0
six==1.13.0 \
    --hash=sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd \
    --hash=sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66
urllib3==1.24.3 \
    --hash=sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4 \
    --hash=sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb
zope.component==4.6 \
    --hash=sha256:ec2afc5bbe611dcace98bb39822c122d44743d635dafc7315b9aef25097db9e6
zope.deferredimport==4.3.1 \
    --hash=sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1 \
    --hash=sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a
zope.deprecation==4.4.0 \
    --hash=sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df \
    --hash=sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113
zope.event==4.4 \
    --hash=sha256:69c27debad9bdacd9ce9b735dad382142281ac770c4a432b533d6d65c4614bcf \
    --hash=sha256:d8e97d165fd5a0997b45f5303ae11ea3338becfe68c401dd88ffd2113fe5cae7
zope.hookable==4.2.0 \
    --hash=sha256:22886e421234e7e8cedc21202e1d0ab59960e40a47dd7240e9659a2d82c51370 \
    --hash=sha256:39912f446e45b4e1f1951b5ffa2d5c8b074d25727ec51855ae9eab5408f105ab \
    --hash=sha256:3adb7ea0871dbc56b78f62c4f5c024851fc74299f4f2a95f913025b076cde220 \
    --hash=sha256:3d7c4b96341c02553d8b8d71065a9366ef67e6c6feca714f269894646bb8268b \
    --hash=sha256:4e826a11a529ed0464ffcecf34b0b7bd1b4928dd5848c5c61bedd7833e8f4801 \
    --hash=sha256:700d68cc30728de1c4c62088a981c6daeaefdf20a0d81995d2c0b7f442c5f88c \
    --hash=sha256:77c82a430cedfbf508d1aa406b2f437363c24fa90c73f577ead0fb5295749b83 \
    --hash=sha256:c1df3929a3666fc5a0c80d60a0c1e6f6ef97c7f6ed2f1b7cf49f3e6f3d4dde15 \
    --hash=sha256:dba8b2dd2cd41cb5f37bfa3f3d82721b8ae10e492944e48ddd90a439227f2893 \
    --hash=sha256:f492540305b15b5591bd7195d61f28946bb071de071cee5d68b6b8414da90fd2
zope.interface==4.6.0 \
    --hash=sha256:086707e0f413ff8800d9c4bc26e174f7ee4c9c8b0302fbad68d083071822316c \
    --hash=sha256:1157b1ec2a1f5bf45668421e3955c60c610e31913cc695b407a574efdbae1f7b \
    --hash=sha256:11ebddf765bff3bbe8dbce10c86884d87f90ed66ee410a7e6c392086e2c63d02 \
    --hash=sha256:14b242d53f6f35c2d07aa2c0e13ccb710392bcd203e1b82a1828d216f6f6b11f \
    --hash=sha256:1b3d0dcabc7c90b470e59e38a9acaa361be43b3a6ea644c0063951964717f0e5 \
    --hash=sha256:20a12ab46a7e72b89ce0671e7d7a6c3c1ca2c2766ac98112f78c5bddaa6e4375 \
    --hash=sha256:298f82c0ab1b182bd1f34f347ea97dde0fffb9ecf850ecf7f8904b8442a07487 \
    --hash=sha256:2f6175722da6f23dbfc76c26c241b67b020e1e83ec7fe93c9e5d3dd18667ada2 \
    --hash=sha256:3b877de633a0f6d81b600624ff9137312d8b1d0f517064dfc39999352ab659f0 \
    --hash=sha256:4265681e77f5ac5bac0905812b828c9fe1ce80c6f3e3f8574acfb5643aeabc5b \
    --hash=sha256:550695c4e7313555549aa1cdb978dc9413d61307531f123558e438871a883d63 \
    --hash=sha256:5f4d42baed3a14c290a078e2696c5f565501abde1b2f3f1a1c0a94fbf6fbcc39 \
    --hash=sha256:62dd71dbed8cc6a18379700701d959307823b3b2451bdc018594c48956ace745 \
    --hash=sha256:7040547e5b882349c0a2cc9b50674b1745db551f330746af434aad4f09fba2cc \
    --hash=sha256:7e099fde2cce8b29434684f82977db4e24f0efa8b0508179fce1602d103296a2 \
    --hash=sha256:7e5c9a5012b2b33e87980cee7d1c82412b2ebabcb5862d53413ba1a2cfde23aa \
    --hash=sha256:81295629128f929e73be4ccfdd943a0906e5fe3cdb0d43ff1e5144d16fbb52b1 \
    --hash=sha256:95cc574b0b83b85be9917d37cd2fad0ce5a0d21b024e1a5804d044aabea636fc \
    --hash=sha256:968d5c5702da15c5bf8e4a6e4b67a4d92164e334e9c0b6acf080106678230b98 \
    --hash=sha256:9e998ba87df77a85c7bed53240a7257afe51a07ee6bc3445a0bf841886da0b97 \
    --hash=sha256:a0c39e2535a7e9c195af956610dba5a1073071d2d85e9d2e5d789463f63e52ab \
    --hash=sha256:a15e75d284178afe529a536b0e8b28b7e107ef39626a7809b4ee64ff3abc9127 \
    --hash=sha256:a6a6ff82f5f9b9702478035d8f6fb6903885653bff7ec3a1e011edc9b1a7168d \
    --hash=sha256:b639f72b95389620c1f881d94739c614d385406ab1d6926a9ffe1c8abbea23fe \
    --hash=sha256:bad44274b151d46619a7567010f7cde23a908c6faa84b97598fd2f474a0c6891 \
    --hash=sha256:bbcef00d09a30948756c5968863316c949d9cedbc7aabac5e8f0ffbdb632e5f1 \
    --hash=sha256:d788a3999014ddf416f2dc454efa4a5dbeda657c6aba031cf363741273804c6b \
    --hash=sha256:eed88ae03e1ef3a75a0e96a55a99d7937ed03e53d0cffc2451c208db445a2966 \
    --hash=sha256:f99451f3a579e73b5dd58b1b08d1179791d49084371d9a47baad3b22417f0317
zope.proxy==4.3.3 \
    --hash=sha256:04646ac04ffa9c8e32fb2b5c3cd42995b2548ea14251f3c21ca704afae88e42c \
    --hash=sha256:07b6bceea232559d24358832f1cd2ed344bbf05ca83855a5b9698b5f23c5ed60 \
    --hash=sha256:1ef452cc02e0e2f8e3c917b1a5b936ef3280f2c2ca854ee70ac2164d1655f7e6 \
    --hash=sha256:22bf61857c5977f34d4e391476d40f9a3b8c6ab24fb0cac448d42d8f8b9bf7b2 \
    --hash=sha256:299870e3428cbff1cd9f9b34144e76ecdc1d9e3192a8cf5f1b0258f47a239f58 \
    --hash=sha256:2bfc36bfccbe047671170ea5677efd3d5ab730a55d7e45611d76d495e5b96766 \
    --hash=sha256:32e82d5a640febc688c0789e15ea875bf696a10cf358f049e1ed841f01710a9b \
    --hash=sha256:3b2051bdc4bc3f02fa52483f6381cf40d4d48167645241993f9d7ebbd142ed9b \
    --hash=sha256:3f734bd8a08f5185a64fb6abb8f14dc97ec27a689ca808fb7a83cdd38d745e4f \
    --hash=sha256:3f78dd8de3112df8bbd970f0916ac876dc3fbe63810bd1cf7cc5eec4cbac4f04 \
    --hash=sha256:4eabeb48508953ba1f3590ad0773b8daea9e104eec66d661917e9bbcd7125a67 \
    --hash=sha256:4f05ecc33808187f430f249cb1ccab35c38f570b181f2d380fbe253da94b18d8 \
    --hash=sha256:4f4f4cbf23d3afc1526294a31e7b3eaa0f682cc28ac5366065dc1d6bb18bd7be \
    --hash=sha256:5483d5e70aacd06f0aa3effec9fed597c0b50f45060956eeeb1203c44d4338c3 \
    --hash=sha256:56a5f9b46892b115a75d0a1f2292431ad5988461175826600acc69a24cb3edee \
    --hash=sha256:64bb63af8a06f736927d260efdd4dfc5253d42244f281a8063e4b9eea2ddcbc5 \
    --hash=sha256:653f8cbefcf7c6ac4cece2cdef367c4faa2b7c19795d52bd7cbec11a8739a7c1 \
    --hash=sha256:664211d63306e4bd4eec35bf2b4bd9db61c394037911cf2d1804c43b511a49f1 \
    --hash=sha256:6651e6caed66a8fff0fef1a3e81c0ed2253bf361c0fdc834500488732c5d16e9 \
    --hash=sha256:6c1fba6cdfdf105739d3069cf7b07664f2944d82a8098218ab2300a82d8f40fc \
    --hash=sha256:6e64246e6e9044a4534a69dca1283c6ddab6e757be5e6874f69024329b3aa61f \
    --hash=sha256:838390245c7ec137af4993c0c8052f49d5ec79e422b4451bfa37fee9b9ccaa01 \
    --hash=sha256:856b410a14793069d8ba35f33fff667213ea66f2df25a0024cc72a7493c56d4c \
    --hash=sha256:8b932c364c1d1605a91907a41128ed0ee8a2d326fc0fafb2c55cd46f545f4599 \
    --hash=sha256:9086cf6d20f08dae7f296a78f6c77d1f8d24079d448f023ee0eb329078dd35e1 \
    --hash=sha256:9698533c14afa0548188de4968a7932d1f3f965f3f5ba1474de673596bb875af \
    --hash=sha256:9b12b05dd7c28f5068387c1afee8cb94f9d02501e7ef495a7c5c7e27139b96ad \
    --hash=sha256:a884c7426a5bc6fb7fc71a55ad14e66818e13f05b78b20a6f37175f324b7acb8 \
    --hash=sha256:abe9e7f1a3e76286c5f5baf2bf5162d41dc0310da493b34a2c36555f38d928f7 \
    --hash=sha256:bd6fde63b015a27262be06bd6bbdd895273cc2bdf2d4c7e1c83711d26a8fbace \
    --hash=sha256:bda7c62c954f47b87ed9a89f525eee1b318ec7c2162dfdba76c2ccfa334e0caa \
    --hash=sha256:be8a4908dd3f6e965993c0068b006bdbd0474fbcbd1da4893b49356e73fc1557 \
    --hash=sha256:ced65fc3c7d7205267506d854bb1815bb445899cca9d21d1d4b949070a635546 \
    --hash=sha256:dac4279aa05055d3897ab5e5ee5a7b39db121f91df65a530f8b1ac7f9bd93119 \
    --hash=sha256:e4f1863056e3e4f399c285b67fa816f411a7bfa1c81ef50e186126164e396e59 \
    --hash=sha256:ecd85f68b8cd9ab78a0141e87ea9a53b2f31fd9b1350a1c44da1f7481b5363ef \
    --hash=sha256:ed269b83750413e8fc5c96276372f49ee3fcb7ed61c49fe8e5a67f54459a5a4a \
    --hash=sha256:f19b0b80cba73b204dee68501870b11067711d21d243fb6774256d3ca2e5391f \
    --hash=sha256:ffdafb98db7574f9da84c489a10a5d582079a888cb43c64e9e6b0e3fe1034685
# Contains the requirements for the letsencrypt package.
#
# Since the letsencrypt package depends on certbot and using pip with hashes
# requires that all installed packages have hashes listed, this allows
# dependency-requirements.txt to be used without requiring a hash for a
# (potentially unreleased) Certbot package.
letsencrypt==0.7.0 \
    --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
    --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==1.0.0 \
    --hash=sha256:8d074cff89dee002dec1c47cb0da04ea8e0ede8d68838b6d54aa41580d9262df \
    --hash=sha256:86b82d31db19fffffb0d6b218951e2121ef514e3ff659aa042deaf92a33e302a
acme==1.0.0 \
    --hash=sha256:f6972e436e76f7f1e395e81e149f8713ca8462d465b14993bddc53fb18a40644 \
    --hash=sha256:6a08f12f848ce563b50bca421ba9db653df9f82cfefeaf8aba517f046d1386c2
certbot-apache==1.0.0 \
    --hash=sha256:e591d0cf773ad33ee978f7adb1b69288eac2c8847c643b06e70260e707626f8e \
    --hash=sha256:7335ab5687a0a47d9041d9e13f3a2d67d0e8372da97ab639edb31c14b787cd68
certbot-nginx==1.0.0 \
    --hash=sha256:ce8a2e51165da7c15bfdc059cd6572d0f368c078f1e1a77633a2773310b2f231 \
    --hash=sha256:63b4ae09d4f1c9ef0a1a2a49c3f651d8a7cb30303ec6f954239e987c5da45dc4
UNLIKELY_EOF
    # -------------------------------------------------------------------------
    cat << "UNLIKELY_EOF" > "$TEMP_DIR/pipstrap.py"
#!/usr/bin/env python
"""A small script that can act as a trust root for installing pip >=8
Embed this in your project, and your VCS checkout is all you have to trust. In
a post-peep era, this lets you claw your way to a hash-checking version of pip,
with which you can install the rest of your dependencies safely. All it assumes
is Python 2.6 or better and *some* version of pip already installed. If
anything goes wrong, it will exit with a non-zero status code.
"""
# This is here so embedded copies are MIT-compliant:
# Copyright (c) 2016 Erik Rose
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
from __future__ import print_function
from distutils.version import StrictVersion
from hashlib import sha256
from os import environ
from os.path import join
from shutil import rmtree
try:
    from subprocess import check_output
except ImportError:
    from subprocess import CalledProcessError, PIPE, Popen
    def check_output(*popenargs, **kwargs):
        if 'stdout' in kwargs:
            raise ValueError('stdout argument not allowed, it will be '
                             'overridden.')
        process = Popen(stdout=PIPE, *popenargs, **kwargs)
        output, unused_err = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise CalledProcessError(retcode, cmd)
        return output
import sys
from tempfile import mkdtemp
try:
    from urllib2 import build_opener, HTTPHandler, HTTPSHandler
except ImportError:
    from urllib.request import build_opener, HTTPHandler, HTTPSHandler
try:
    from urlparse import urlparse
except ImportError:
    from urllib.parse import urlparse  # 3.4
__version__ = 1, 5, 1
PIP_VERSION = '9.0.1'
DEFAULT_INDEX_BASE = 'https://pypi.python.org'
# wheel has a conditional dependency on argparse:
maybe_argparse = (
    [('18/dd/e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/'
      'argparse-1.4.0.tar.gz',
      '62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4')]
    if sys.version_info < (2, 7, 0) else [])
PACKAGES = maybe_argparse + [
    # Pip has no dependencies, as it vendors everything:
    ('11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/'
     'pip-{0}.tar.gz'.format(PIP_VERSION),
     '09f243e1a7b461f654c26a725fa373211bb7ff17a9300058b205c61658ca940d'),
    # This version of setuptools has only optional dependencies:
    ('37/1b/b25507861991beeade31473868463dad0e58b1978c209de27384ae541b0b/'
     'setuptools-40.6.3.zip',
     '3b474dad69c49f0d2d86696b68105f3a6f195f7ab655af12ef9a9c326d2b08f8'),
    ('c9/1d/bd19e691fd4cfe908c76c429fe6e4436c9e83583c4414b54f6c85471954a/'
     'wheel-0.29.0.tar.gz',
     '1ebb8ad7e26b448e9caa4773d2357849bf80ff9e313964bcaf79cbf0201a1648')
]
class HashError(Exception):
    def __str__(self):
        url, path, actual, expected = self.args
        return ('{url} did not match the expected hash {expected}. Instead, '
                'it was {actual}. The file (left at {path}) may have been '
                'tampered with.'.format(**locals()))
def hashed_download(url, temp, digest):
    """Download ``url`` to ``temp``, make sure it has the SHA-256 ``digest``,
    and return its path."""
    # Based on pip 1.4.1's URLOpener but with cert verification removed. Python
    # >=2.7.9 verifies HTTPS certs itself, and, in any case, the cert
    # authenticity has only privacy (not arbitrary code execution)
    # implications, since we're checking hashes.
    def opener(using_https=True):
        opener = build_opener(HTTPSHandler())
        if using_https:
            # Strip out HTTPHandler to prevent MITM spoof:
            for handler in opener.handlers:
                if isinstance(handler, HTTPHandler):
                    opener.handlers.remove(handler)
        return opener
    def read_chunks(response, chunk_size):
        while True:
            chunk = response.read(chunk_size)
            if not chunk:
                break
            yield chunk
    parsed_url = urlparse(url)
    response = opener(using_https=parsed_url.scheme == 'https').open(url)
    path = join(temp, parsed_url.path.split('/')[-1])
    actual_hash = sha256()
    with open(path, 'wb') as file:
        for chunk in read_chunks(response, 4096):
            file.write(chunk)
            actual_hash.update(chunk)
    actual_digest = actual_hash.hexdigest()
    if actual_digest != digest:
        raise HashError(url, path, actual_digest, digest)
    return path
def get_index_base():
    """Return the URL to the dir containing the "packages" folder.
    Try to wring something out of PIP_INDEX_URL, if set. Hack "/simple" off the
    end if it's there; that is likely to give us the right dir.
    """
    env_var = environ.get('PIP_INDEX_URL', '').rstrip('/')
    if env_var:
        SIMPLE = '/simple'
        if env_var.endswith(SIMPLE):
            return env_var[:-len(SIMPLE)]
        else:
            return env_var
    else:
        return DEFAULT_INDEX_BASE
def main():
    python = sys.executable or 'python'
    pip_version = StrictVersion(check_output([python, '-m', 'pip', '--version'])
                                .decode('utf-8').split()[1])
    has_pip_cache = pip_version >= StrictVersion('6.0')
    index_base = get_index_base()
    temp = mkdtemp(prefix='pipstrap-')
    try:
        downloads = [hashed_download(index_base + '/packages/' + path,
                                     temp,
                                     digest)
                     for path, digest in PACKAGES]
        # Calling pip as a module is the preferred way to avoid problems about pip self-upgrade.
        command = [python, '-m', 'pip', 'install', '--no-index', '--no-deps', '-U']
        # Disable cache since it is not used and it otherwise sometimes throws permission warnings:
        command.extend(['--no-cache-dir'] if has_pip_cache else [])
        command.extend(downloads)
        check_output(command)
    except HashError as exc:
        print(exc)
    except Exception:
        rmtree(temp)
        raise
    else:
        rmtree(temp)
        return 0
    return 1
if __name__ == '__main__':
    sys.exit(main())
UNLIKELY_EOF
    # -------------------------------------------------------------------------
    # Set PATH so pipstrap upgrades the right (v)env:
    PATH="$VENV_BIN:$PATH" "$VENV_BIN/python" "$TEMP_DIR/pipstrap.py"
    set +e
    if [ "$VERBOSE" = 1 ]; then
      "$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt"
    else
      PIP_OUT=`"$VENV_BIN/pip" install --disable-pip-version-check --no-cache-dir --require-hashes -r "$TEMP_DIR/letsencrypt-auto-requirements.txt" 2>&amp;1`
    fi
    PIP_STATUS=$?
    set -e
    if [ "$PIP_STATUS" != 0 ]; then
      # Report error. (Otherwise, be quiet.)
      error "Had a problem while installing Python packages."
      if [ "$VERBOSE" != 1 ]; then
        error
        error "pip prints the following errors: "
        error "====================================================="
        error "$PIP_OUT"
        error "====================================================="
        error
        error "Certbot has problem setting up the virtual environment."
        if `echo $PIP_OUT | grep -q Killed` || `echo $PIP_OUT | grep -q "allocate memory"` ; then
          error
          error "Based on your pip output, the problem can likely be fixed by "
          error "increasing the available memory."
        else
          error
          error "We were not be able to guess the right solution from your pip "
          error "output."
        fi
        error
        error "Consult https://certbot.eff.org/docs/install.html#problems-with-python-virtual-environment"
        error "for possible solutions."
        error "You may also find some support resources at https://certbot.eff.org/support/ ."
      fi
      rm -rf "$VENV_PATH"
      exit 1
    fi
    if [ -d "$OLD_VENV_PATH" -a ! -L "$OLD_VENV_PATH" ]; then
      rm -rf "$OLD_VENV_PATH"
      ln -s "$VENV_PATH" "$OLD_VENV_PATH"
    fi
    say "Installation succeeded."
  fi
  if [ "$INSTALL_ONLY" = 1 ]; then
    say "Certbot is installed."
    exit 0
  fi
  "$VENV_BIN/letsencrypt" "[email protected]"
else
  # Phase 1: Upgrade certbot-auto if necessary, then self-invoke.
  #
  # Each phase checks the version of only the thing it is responsible for
  # upgrading. Phase 1 checks the version of the latest release of
  # certbot-auto (which is always the same as that of the certbot
  # package). Phase 2 checks the version of the locally installed certbot.
  export PHASE_1_VERSION="$LE_AUTO_VERSION"
  if [ ! -f "$VENV_BIN/letsencrypt" ]; then
    if ! OldVenvExists; then
      if [ "$HELP" = 1 ]; then
        echo "$USAGE"
        exit 0
      fi
      # If it looks like we've never bootstrapped before, bootstrap:
      Bootstrap
    fi
  fi
  if [ "$OS_PACKAGES_ONLY" = 1 ]; then
    say "OS packages installed."
    exit 0
  fi
  DeterminePythonVersion "NOCRASH"
  # Don't warn about file permissions if the user disabled the check or we
  # can't find an up-to-date Python.
  if [ "$PYVER" -ge "$MIN_PYVER" -a "$NO_PERMISSIONS_CHECK" != 1 ]; then
    # If the script fails for some reason, don't break certbot-auto.
    set +e
    # Suppress unexpected error output.
    CHECK_PERM_OUT=$(CheckPathPermissions "$LE_PYTHON" "$0" 2>/dev/null)
    CHECK_PERM_STATUS="$?"
    set -e
    # Only print output if the script ran successfully and it actually produced
    # output. The latter check resolves
    # https://github.com/certbot/certbot/issues/7012.
    if [ "$CHECK_PERM_STATUS" = 0 -a -n "$CHECK_PERM_OUT" ]; then
      error "$CHECK_PERM_OUT"
    fi
  fi
  if [ "$NO_SELF_UPGRADE" != 1 ]; then
    TEMP_DIR=$(TempDir)
    trap 'rm -rf "$TEMP_DIR"' EXIT
    # ---------------------------------------------------------------------------
    cat << "UNLIKELY_EOF" > "$TEMP_DIR/fetch.py"
"""Do downloading and JSON parsing without additional dependencies. ::
    # Print latest released version of LE to stdout:
    python fetch.py --latest-version
    # Download letsencrypt-auto script from git tag v1.2.3 into the folder I'm
    # in, and make sure its signature verifies:
    python fetch.py --le-auto-script v1.2.3
On failure, return non-zero.
"""
from __future__ import print_function, unicode_literals
from distutils.version import LooseVersion
from json import loads
from os import devnull, environ
from os.path import dirname, join
import re
import ssl
from subprocess import check_call, CalledProcessError
from sys import argv, exit
try:
    from urllib2 import build_opener, HTTPHandler, HTTPSHandler
    from urllib2 import HTTPError, URLError
except ImportError:
    from urllib.request import build_opener, HTTPHandler, HTTPSHandler
    from urllib.error import HTTPError, URLError
PUBLIC_KEY = environ.get('LE_AUTO_PUBLIC_KEY', """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6MR8W/galdxnpGqBsYbq
OzQb2eyW15YFjDDEMI0ZOzt8f504obNs920lDnpPD2/KqgsfjOgw2K7xWDJIj/18
xUvWPk3LDkrnokNiRkA3KOx3W6fHycKL+zID7zy+xZYBuh2fLyQtWV1VGQ45iNRp
9+Zo7rH86cdfgkdnWTlNSHyTLW9NbXvyv/E12bppPcEvgCTAQXgnDVJ0/sqmeiij
n9tTFh03aM+R2V/21h8aTraAS24qiPCz6gkmYGC8yr6mglcnNoYbsLNYZ69zF1XH
cXPduCPdPdfLlzVlKK1/U7hkA28eG3BIAMh6uJYBRJTpiGgaGdPd7YekUB8S6cy+
CQIDAQAB
-----END PUBLIC KEY-----
""")
class ExpectedError(Exception):
    """A novice-readable exception that also carries the original exception for
    debugging"""
class HttpsGetter(object):
    def __init__(self):
        """Build an HTTPS opener."""
        # Based on pip 1.4.1's URLOpener
        # This verifies certs on only Python >=2.7.9, and when NO_CERT_VERIFY isn't set.
        if environ.get('NO_CERT_VERIFY') == '1' and hasattr(ssl, 'SSLContext'):
            self._opener = build_opener(HTTPSHandler(context=cert_none_context()))
        else:
            self._opener = build_opener(HTTPSHandler())
        # Strip out HTTPHandler to prevent MITM spoof:
        for handler in self._opener.handlers:
            if isinstance(handler, HTTPHandler):
                self._opener.handlers.remove(handler)
    def get(self, url):
        """Return the document contents pointed to by an HTTPS URL.
        If something goes wrong (404, timeout, etc.), raise ExpectedError.
        """
        try:
            # socket module docs say default timeout is None: that is, no
            # timeout
            return self._opener.open(url, timeout=30).read()
        except (HTTPError, IOError) as exc:
            raise ExpectedError("Couldn't download %s." % url, exc)
def write(contents, dir, filename):
    """Write something to a file in a certain directory."""
    with open(join(dir, filename), 'wb') as file:
        file.write(contents)
def latest_stable_version(get):
    """Return the latest stable release of letsencrypt."""
    metadata = loads(get(
        environ.get('LE_AUTO_JSON_URL',
                    'https://pypi.python.org/pypi/certbot/json')).decode('UTF-8'))
    # metadata['info']['version'] actually returns the latest of any kind of
    # release release, contrary to https://wiki.python.org/moin/PyPIJSON.
    # The regex is a sufficient regex for picking out prereleases for most
    # packages, LE included.
    return str(max(LooseVersion(r) for r
                   in metadata['releases'].keys()
                   if re.match('^[0-9.]+$', r)))
def verified_new_le_auto(get, tag, temp_dir):
    """Return the path to a verified, up-to-date letsencrypt-auto script.
    If the download's signature does not verify or something else goes wrong
    with the verification process, raise ExpectedError.
    """
    le_auto_dir = environ.get(
        'LE_AUTO_DIR_TEMPLATE',
        'https://raw.githubusercontent.com/certbot/certbot/%s/'
        'letsencrypt-auto-source/') % tag
    write(get(le_auto_dir + 'letsencrypt-auto'), temp_dir, 'letsencrypt-auto')
    write(get(le_auto_dir + 'letsencrypt-auto.sig'), temp_dir, 'letsencrypt-auto.sig')
    write(PUBLIC_KEY.encode('UTF-8'), temp_dir, 'public_key.pem')
    try:
        with open(devnull, 'w') as dev_null:
            check_call(['openssl', 'dgst', '-sha256', '-verify',
                        join(temp_dir, 'public_key.pem'),
                        '-signature',
                        join(temp_dir, 'letsencrypt-auto.sig'),
                        join(temp_dir, 'letsencrypt-auto')],
                       stdout=dev_null,
                       stderr=dev_null)
    except CalledProcessError as exc:
        raise ExpectedError("Couldn't verify signature of downloaded "
                            "certbot-auto.", exc)
def cert_none_context():
    """Create a SSLContext object to not check hostname."""
    # PROTOCOL_TLS isn't available before 2.7.13 but this code is for 2.7.9+, so use this.
    context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
    context.verify_mode = ssl.CERT_NONE
    return context
def main():
    get = HttpsGetter().get
    flag = argv[1]
    try:
        if flag == '--latest-version':
            print(latest_stable_version(get))
        elif flag == '--le-auto-script':
            tag = argv[2]
            verified_new_le_auto(get, tag, dirname(argv[0]))
    except ExpectedError as exc:
        print(exc.args[0], exc.args[1])
        return 1
    else:
        return 0
if __name__ == '__main__':
    exit(main())
UNLIKELY_EOF
    # ---------------------------------------------------------------------------
    if [ "$PYVER" -lt "$MIN_PYVER" ]; then
      error "WARNING: couldn't find Python $MIN_PYTHON_VERSION+ to check for updates."
    elif ! REMOTE_VERSION=`"$LE_PYTHON" "$TEMP_DIR/fetch.py" --latest-version` ; then
      error "WARNING: unable to check for updates."
    fi
    LE_VERSION_STATE=`CompareVersions "$LE_PYTHON" "$LE_AUTO_VERSION" "$REMOTE_VERSION"`
    if [ "$LE_VERSION_STATE" = "UNOFFICIAL" ]; then
      say "Unofficial certbot-auto version detected, self-upgrade is disabled: $LE_AUTO_VERSION"
    elif [ "$LE_VERSION_STATE" = "OUTDATED" ]; then
      say "Upgrading certbot-auto $LE_AUTO_VERSION to $REMOTE_VERSION..."
      # Now we drop into Python so we don't have to install even more
      # dependencies (curl, etc.), for better flow control, and for the option of
      # future Windows compatibility.
      "$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
      # Install new copy of certbot-auto.
      # TODO: Deal with quotes in pathnames.
      say "Replacing certbot-auto..."
      # Clone permissions with cp. chmod and chown don't have a --reference
      # option on macOS or BSD, and stat -c on Linux is stat -f on macOS and BSD:
      cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
      cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
      # Using mv rather than cp leaves the old file descriptor pointing to the
      # original copy so the shell can continue to read it unmolested. mv across
      # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
      # cp is unlikely to fail if the rm doesn't.
      mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
    fi  # A newer version is available.
  fi  # Self-upgrading is allowed.
  RerunWithArgs --le-auto-phase2 "[email protected]"
fi

3 Create cron job for this script

/opt/letsencrypt/le-renew.sh yourdomain.com

If the script is complaining about domain name.

Open folder “/etc/letsencrypt/renewal” see if your domain name configuration file is there or attached with -0001 etc. e.g. “yourdomain.com-0001” “anotherdomain.com-0005” If so, use that string instead of your domain name, so:

/opt/letsencrypt/le-renew.sh yourdomain.com-0001
/opt/letsencrypt/le-renew.sh anotherdomain.com-0005

3 Bonus

We can also configure “MAILTO” variable for Cron jobs then we will be able to receive output of this script via email, following command also log the results to “/var/log/le-renew.log”

/opt/letsencrypt/le-renew.sh yourdomain.com | tee /var/log/le-renew.log

Linux Server Tips

Keywords: Linux Server Tips, Linux commands

1 Check last login details, who, when

“w” to check last start up time, currently logged in users

“last” to check logins

“who” Currently logged in users’ details

“lastlog” Users’ last login time

“whoami” Show current username

“finger” Find user information

“id” Current user uid, gid and group information

2 Find ports

netstat -anp | grep 443

lsof -i:443

3 Compile source code

“ar” extract archive, archived installation files

“./configure” configure to fit current systems

“make” compile the source code into binary files e.g. executables

“make install” install the compiled program

4 Linux Directories

“/boot”: Linux kernel, boot configuration etc.

“/bin”: Basic user commands, can be run by users

“/dev”: HDD, Keyboard, Mouse, DVD/CD-ROM device files

“/etc”: Configuration files

“/home”: Users’ working directories (home directory etc.)

“/sbin”: Basic management commands, normally only accessable by administrators

“/usr”: Application, source code files, documents etc.

“/var”: Logs, user mail, process data

“/tmp”: Temporary files

5 Common log files

“/var/log/messages”: Kernel and public messages

“/var/log/cron”: Scheduled Tasks/Crontab

“/var/log/dmesg”: System boot log

“/var/log/maillog”: System mail log

“/var/log/secure”: Access control log

6 Common Linux boot files

“/etc/fstab”: Auto mount on boot

“/etc/initab”: Define default boot level

“/etc/rc.local”: Define custom boot tasks

7 suid, sgid, sticky bit

suid: Run as the owner of the file/binary

sgid: Files created within the folder inherits the folder owner’s permission

sticky bit: Users can only modify, delete wheir own files

8 Check process: “ps”, “top”

9 Check process scheduling: “at”, “crontab”, “batch”, “kill”

10 Extract files

1.*.tarExtract using tar -xvf
2.*.gz Extract using gzip -d OR gunzip
3.*.tar.gz Extract using tar -xzf
4.*.bz2 Extract using bzip2 -d OR bunzip2
5.*.tar.bz2 Extract using tar -xjf
6.*.Z Extract using uncompress
7.*.tar.Z Extract using tar -xZf
8.*.rar Extract using unrar e
9.*.zip Extract using unzip

11 Mounting Windows share

mount -t cifs -o username=windowsusername, password="windowspassword" //ipaddress/folder mnt/linuxtargetfolder

OR

mount.cifs //ipaddress/folder /mnt.linuxtargetfolder -o username="windowsusername", password="windowspassword"