インストール - Zsh

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

Zshはシェルの一種で、Linux等の標準シェルであるbashよりも便利な機能を持ったシェルである。

Linuxにてターミナルでコマンドを実行することが多々あるが、zshに切り替えることで、作業効率を上げることができる。

最新のZshはZshの公式Webサイトで確認できる。


Zshのインストール

パッケージ管理システムからインストール

# RHEL
sudo dnf install zsh

# SUSE
sudo zypper install zsh

# Raspberry Pi
sudo apt install zsh


ソースコードからインストール

まず、Zshのビルドに必要なライブラリをインストールする。

# RHEL
sudo subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms
sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
sudo dnf install ncurses-devel

# SUSE
sudo zypper install ncurses-devel

# Raspberry Pi
sudo apt install libncurses-dev


次に、以下に示すZshの公式WebサイトまたはSouceforgeから、Zshのソースコードをダウンロードする。


Zshのビルドでは、ビルドディレクトリを作成しないこと。

wget https://sourceforge.net/projects/zsh/files/zsh/<バージョン名>/zsh-<バージョン名>.tar.xz/download -O zsh-<バージョン名>.tar.xz
tar xf zsh-<バージョン名>.tar.xz
cd zsh-<バージョン名>


次に、Zshをビルドおよびインストールする。
ここで、--enable-multibyteオプションは、マルチバイトを有効にするオプションである。

./configure --enable-multibyte --prefix=<Zshのインストールディレクトリ>
make -j $(nproc)
make install


※注意
configureスクリプトの実行において、以下に示すエラーが出力される時がある。

config.status: error: cannot find input file: `config.h.in'


この時、autoheaderコマンドを実行して、config.h.inファイルを作成する。

autoheader



Zshの使用

Zshを利用可能なシェル一覧に追加する。
/etc/shellsファイルにzshのパスを追加することにより、chshコマンド、または、usermodコマンドでログインシェルの変更が可能となる。

echo "/<zshのインストールディレクトリ>/bin/zsh" | sudo tee -a /etc/shells


次に、ユーザのシェルを変更する。(コマンドを実行するとパスワードの入力が必要となる)

chsh -s /<zshのインストールディレクトリ>/bin/zsh $USER
# または
sudo usermod --shell /<zshのインストールディレクトリ>/bin/zsh $USER


ログインシェルが変更されているかどうかを確認する。

grep $USER /etc/passwd


再ログイン、または、PCを再起動する。

すると、以下の文言が表示される。これは、Zshに設定ファイルが存在しないために表示される。
ここでは、 0を入力して空の設定ファイルを作成する。

This is the Z Shell configuration function for new users, zsh-newuser-install.
You are seeing this message because you have no zsh startup files(the files .zshenv, .zprofile, .zshrc, .zlogin in the directory~).
This function can help you with a few settings that should make your use of the shell easier.

You can:

(q)  Quit and do nothing.  The function will be run again next time.

(0)  Exit, creating the file ~/.zshrc containing just a comment.
    That will prevent this function being run again.

(1)  Continue to the main menu.

--- Type one of the keys in parentheses ---



エラー

Zshを起動した時、以下のようなエラーが発生する場合がある。

stty: invalid integer argument〜


Zshでは、^(キャレット)は拡張グロブ文字であり、コマンド処理のファイル名拡張部分で認識される。

例えば、^Mは、Mにマッチするものを除く全てのファイル名にマッチする。
この時、stty eraseに続き、カレントディレクトリにMという名前のファイルがあれば、それを除く全てのファイル名を展開するということである。

このエラーを回避するには、^(キャレット)文字を使用している箇所を、引用またはエスケープする必要がある。

'^M'
または
\^M


または、~/.zshrcファイルにおいて、Zshの拡張グロブを無効にする。

 setopt NO_EXTENDED_GLOB



Zshの設定例

Zshの設定ファイルを作成した後、以下に示すような設定を記述する。

vi ~/.zshrc


 # ~/.zshrcファイル
 
 # Don't logout with Ctrl + D
 setopt IGNOREEOF
 
 # Don't overwrite with redirect
 setopt NOCLOBBER
 
 # Use Japanese
 # export LANG=ja_JP.UTF-8
 
 # Use color
 autoload -Uz colors
 colors
 
 # Enable auto-completion wih [Tab] key
 autoload -Uz compinit
 compinit
 
 # Enable Emacs-like operations
 bindkey -e
 bindkey ";5C" emacs-forward-word    # Ctrl-Right to move the cursor
 bindkey ";5D" emacs-backward-word   # Ctrl-Left to move the cursor
 
 # Share history with other terminals
 setopt share_history
 
 # Don't show duplicates in history
 setopt HIST_IGNORE_ALL_DUPS
 
 # Ignore duplicate histories
 setopt HIST_IGNORE_DUPS
 
 # Delete empty line from history
 setopt HIST_REDUCE_BLANKS
 
 # Ignore commands that start with blank space
 setopt HIST_IGNORE_SPACE
 
 # Don't add history command & fc commands to history
 setopt HIST_NO_STORE
 
 HISTFILE=~/.zsh_history
 HISTSIZE=100
 SAVEHIST=100
 
 # If command you entered doesn't exist and matches the directory name, cd to directory
 # Ex. Type /usr/bin to go to /usr/bin directory
 setopt auto_cd
 
 # Add directory you cd to to directory stack
 # "The directory stack" is history of directories you've been to so far
 # cd + [Tab] will show directory history and take you to it
 setopt auto_pushd
 
 # Delete duplicates from pushd
 setopt pushd_ignore_dups
 
 # Fix command error
 setopt correct
 SPROMPT="correct: $RED%R$DEFAULT -> $GREEN%r$DEFAULT ? [Yes/No/Abort/Edit] => "
 
 # Global Alias
 alias -g cd=' cd -P'
 alias -g rm='rm -iv'
 alias -g cp='cp -i'
 alias -g mv='mv -iv'
 alias -g ll=' ls -hlvF --group-directories-first --color'
 alias -g cat=' cat -n'
 alias -g less=' less -n'
 alias -g grep=' grep -i'
 alias -g usermod='usermod -a'
 alias -g en=' LANG=C LANGUAGE=C LC_ALL=C'
 alias -g jp='LANG=ja_JP.UTF-8'
 alias -g mount='mount -o ro,noload'
 alias -g umount='umount -fl'
 alias -g L='| less'
 alias -g H='| head'
 alias -g G='| grep'
 alias -g GI='| grep -ri'
 alias -g D='--detail'
 alias -g progress='& progress -mp $!'
 alias -g nano='nano -lmS'
 alias -g kate='kate 1>&/dev/null 2>&1'
 alias -g skate='kdesu /usr/bin/kate 1>&/dev/null 2>&1'
 
 # Alias
 alias which=' which'
 alias clear=' clear && echo -en "\e[3J"'
 alias hclear=' rm -rf ~/.zsh_history 1>/dev/null && touch ~/.zsh_history 1>/dev/null'
 alias igrep=' sudo zypper search -i'
 alias asearch=' sudo zypper search -uv'
 alias repoclean=' sudo zypper clean -a'
 alias skate='kdesu /usr/bin/kate'
 alias scode='code --user-data-dir=$HOME/Program/VScode_root_project'
 alias suse=' cat /etc/SUSE-brand'
 alias mksingless=' sudo snapper create -t single -d'
 alias upoweroff=' sudo systemctl poweroff'
 alias ureboot=' sudo systemctl reboot'
 alias startx=' startx'
 alias exit=' exit'
 alias gexit=' killall -3 gnome-shell > /dev/null 2>&1; echo <パスワード> | sudo -S systemctl stop graphical.target; echo <パスワード> | sudo -S systemctl isolate multi-user.target'
 alias kexit=' killall plasmashell; echo <パスワード> | sudo -S systemctl stop graphical.target; echo <パスワード> | sudo -S systemctl restart multi-user.target'
 alias gnome=' sudo systemctl isolate graphical.target'
 alias kde=' sudo systemctl isolate graphical.target'
 alias uoff=' dbus-send --print-reply=literal --system --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.PowerOff" boolean:true'
 alias ureboot=' dbus-send --print-reply=literal --system --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.Reboot" boolean:true'
 alias fw=' sudo firewall-cmd'
 alias fwr='sudo firewall-cmd --reload'
 alias fwp='sudo firewall-cmd --permanent'
 alias fwrp='sudo firewall-cmd --runtime-to-permanent'
 alias startnm=' sudo systemctl stop wickedd wicked; sudo systemctl start NetworkManager'
 alias startwicked=' sudo systemctl stop NetworkManager; sudo systemctl start wickedd wicked'
 
 alias plasma=' /usr/bin/kquitapp5 plasmashell; plasmashell > /dev/null 2>&1 & disown; exit'    # Restart Plasma Shell
 alias gshell=' killall -3 gnome-shell > /dev/null 2>&1 & disown; sleep 2; exit'         # Restart GNOME Shell
 alias udesktop='update-desktop-database $HOME/.local/share/applications'                # Update Desktop Entry
 
 alias sshpi='ssh <ユーザ名>@<ホスト名またはIPアドレス> -p <ポート番号> -i <暗号鍵ファイルのフルパス>'
 alias sshpig=' ssh -Y <ユーザ名>@<ホスト名またはIPアドレス> -p <ポート番号> -i <暗号鍵ファイルのフルパス>'  # Connect & Execute SSH GUI-Software Raspberry Pi
 alias sshpine=' ssh <ユーザ名>@<ホスト名またはIPアドレス> -p <ポート番号> -i <暗号鍵ファイルのフルパス>'    # Connect SSH PinePhone
 alias sshvalue=' sshpass -p <パスワード> ssh <ユーザ名>@<ホスト名またはIPアドレス>'                   # Connect SSH Value Server
 alias sshxrea=' sshpass -p <パスワード> ssh <ユーザ名>@<ホスト名またはIPアドレス>'                    # Connect SSH XREA
 alias sshsakura=' sshpass -p <パスワード> ssh <ユーザ名>@<ホスト名またはIPアドレス>'                  # Connect SSH Sakura
 
 # If Install FreeRDP and Windows10(VM) with KVM
 alias rwin10=' /<FreeRDPのインストールディレクトリ>/bin/xfreerdp /u:<仮想マシンのユーザ名> /p:<パスワード> /w:1600 /h:900 +clipboard /sound:rate:44100,channel:2 /drive:<共有ディレクトリ名>,<共有ディレクトリのフルパス> /v:<仮想マシンのIPアドレス>'
 
 # If Install VMware Workstation
 alias vmwarefix=' sudo vmware-modconfig --console --install-all'
 
 # If Install Docker
 alias startdocker=' sudo systemctl restart docker'
 alias stopdocker=' sudo systemctl stop docker'
  
 # Allow backspace and delete keys to be used
 stty erase ^H
 bindkey "^[[3~" delete-char
 
 # Run ls command, after cd command
 function chpwd()
 {
    ls -hlFtr --color=auto
 }
 
 # Directory paths that can be referenced from anywhere
 #cdpath=(~)
 
 # Setting the delimiter
 autoload -Uz select-word-style
 select-word-style default
 zstyle ':zle:*' word-chars "_-./;@"
 zstyle ':zle:*' word-style unspecified
 
 # Disable Ctrl + [s] lock, Ctrl + [q] unlock
 setopt no_flow_control
 
 # Dislay custom prompt
 PROMPT="%(?.%{${fg[red]}%}.%{${fg[red]}%})%n${reset_color}@${fg[green]}%m${reset_color}(%*%) Using Zsh %{${fg[yellow]}%}[%~]%{${reset_color}%}
 > "
 
 # Press [Tab] to display path name completion suggestions, and then press [Tab] to select a path name from suggestions
 # After completion, you will be in menu selection mode, and can use left and right keys to move
 zstyle ':completion:*:default' menu select=2
 
 # Matches uppercase letters with completion
 zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
 
 # Ctrl + [r] for incremental search of history, Ctrl + [s] for reverse order
 bindkey '^r' history-incremental-pattern-search-backward
 bindkey '^s' history-incremental-pattern-search-forward
 
 # Type command halfway through, then narrow it down from history
 # Ex. Type "ls", then Ctrl + [p] to go back through ls commands, Ctrl + [b] to go in reverse order
 autoload -Uz history-search-end
 zle -N history-beginning-search-backward-end history-search-end
 zle -N history-beginning-search-forward-end history-search-end
 bindkey "^p" history-beginning-search-backward-end
 bindkey "^b" history-beginning-search-forward-end
 
 # "cdr" command enabled (directory history enabled even after logout)
 # Show list using "cdr" + [Tab]
 autoload -Uz add-zsh-hook
 autoload -Uz chpwd_recent_dirs cdr
 add-zsh-hook chpwd chpwd_recent_dirs
 
 # The cdr command can now be used to move to directories that are not in history
 zstyle ":chpwd:*" recent-dirs-default true
 
 # Multiple file mv
 # Ex. zmv *.txt *.txt.bk
 autoload -Uz zmv
 alias zmv='noglob zmv -W'
 
 # Prevent prompt from overwriting output with no newlines
 unsetopt promptcr
 
 # If Install Git
 RPROMPT="%{${fg[blue]}%}%{${reset_color}%}"
 autoload -Uz vcs_info
 setopt prompt_subst
 zstyle ':vcs_info:git:*' check-for-changes true
 zstyle ':vcs_info:git:*' stagedstr "%F{yellow}!"
 zstyle ':vcs_info:git:*' unstagedstr "%F{red}+"
 zstyle ':vcs_info:*' formats "%F{green}%c%u[%b]%f"
 zstyle ':vcs_info:*' actionformats '[%b|%a]'
 precmd () { vcs_info }
 RPROMPT=$RPROMPT'${vcs_info_msg_0_}'
 
 # If Install Docker
 export DOCKER_HOST='tcp://localhost:2375'
 
 # Execute mkdir, after cd command
 function mkcd()
 {
    if [ "${#}" -ne 1 ]; then
       echo "Specify Arguments." 1>&2
       return 1
    fi
 
    if [ -d $1 ]; then
       echo "$1 already exists!" 
       cd $1
    else
       mkdir -p $1 && cd $1
    fi
 
    return 0
 }
 
 # man using Web Browser
 function manh()
 {
    if [ "$#" -eq 0 ]; then
       echo "Too few arguments!"
    elif [ "$#" -eq "1" ]; then
       man --html=firefox $1 &
    else
       echo "Too many arguments!"
    fi
 }
 
 # Search for directories and files that exist in a directory
 function lgrep()
 {
    if [ "$#" -eq 1 ]; then
       local IFS_BACKUP=$IFS
       IFS=$'\n\t'
 
       for OBJECT in $(\ls -aA --group-directories-first | \grep -iE "${1}")
       do
          \ls -AdhlF --color "${OBJECT}"
       done
 
       echo ""
 
       IFS=$IFS_BACKUP
    elif [ "$#" -eq 2 ]; then
       # 第1引数で指定したディレクトリが存在するか確認する
       if [ ! -d "$1" ]; then
          echo "Not Exist Directory $1" 1>&2
          return 1
       fi
 
       local IFS_BACKUP=$IFS
       IFS=$'\n\t'
 
       # 上記で定義しているchpwd関数を無効化する
       disable -f chpwd
 
       # 現在のカレントディレクトリを一時的に保存する
       local CURRENTDIR=$(\pwd)
 
       # 第1引数で指定したディレクトリに移動する
       cd "${1}";
 
       # 第2引数で指定したパターンを使用して検索する
       for OBJECT in $(\ls -aA --group-directories-first | \grep -iE "${2}")
       do
          \ls -AdhlF --color "${OBJECT}"
       done
 
       # カレントディレクトリに戻る
       cd "${CURRENTDIR}"
 
       echo ""
 
       IFS=$IFS_BACKUP
 
       # 上記で定義しているchpwd関数を有効化する
       enable -f chpwd
 
       unset -v OBJECT
    else
       echo "Specify Arguments." 1>&2
    fi
 
    return 0
 }
 
 # After searching for a specific file in directory, search the contents that match pattern
 function datagrep()
 {
    if [ "$#" -eq 1 ]; then
       if [ "${1}" = '-h' -o "${1}" = '--h' -o "${1}" = '-help' -o "${1}" = "--help" ]; then
          echo "Usage:"
          echo "   Ex.1: filegrep <File Patern> <File Data Pattern>"
          echo "   Ex.2: filegrep <Search Directory> <File Patern> <File Data Pattern>"
 
          return 0
       fi
    fi
 
    if [ "$#" -eq 2 ]; then
       local IFS_BACKUP=$IFS
       IFS=$''
 
       for OBJECT in $(\find . -type f -iname "${1}" -print0 | \xargs -0 \grep -inE "${2}")
       do
          echo "${OBJECT}"
       done
 
       echo ""
 
       IFS=$IFS_BACKUP
    elif [ "$#" -eq 3 ]; then
       # 第1引数で指定したディレクトリが存在するか確認する
       if [ ! -d "$1" ]; then
          echo "Not Exist Directory $1" 1>&2
          return 1
       fi
 
       local IFS_BACKUP=$IFS
       IFS=$''
 
       # 上記で定義しているchpwd関数を無効化する
       disable -f chpwd
 
       # 現在のカレントディレクトリを一時的に保存する
       local CURRENTDIR=$(\pwd)
 
       # 第1引数で指定したディレクトリに移動する
       cd "${1}";
 
       # 第2引数で指定したパターンを使用して検索する
       for OBJECT in $(\find . -type f -iname "${2}" -print0 | \xargs -0 \grep -inE "${3}")
       do
          echo "${OBJECT}"
       done
 
       # カレントディレクトリに戻る
       cd "${CURRENTDIR}"
 
       echo ""
 
       IFS=$IFS_BACKUP
 
       # 上記で定義しているchpwd関数を有効化する
       enable -f chpwd
 
       unset -v OBJECT
    else
       echo "Specify Arguments." 1>&2
    fi
 
    return 0
 }
 
 function fwl()
 {
    # converts output to zsh array ()
    # @f flag split on new line
    zones=("${(@f)$(sudo firewall-cmd --get-active-zones | grep -v 'interfaces\|sources')}")
 
    for i in $zones; do
       sudo firewall-cmd --zone $i --list-all
    done
 
    echo 'Direct Rules:'
    sudo firewall-cmd --direct --get-all-rules
 }
 
 # Add Environment Variable PATH
 function SetPATH()
 {
    local BEFORE_HOME='$HOME'
    local AFTER_HOME="$HOME"
    local PATH_NAME=$(echo "${1//"${BEFORE_HOME}"/"${AFTER_HOME}"}")
    
    local SLASH=$(echo "${PATH_NAME: -1:1}")
    if [ "${SLASH}" = "/" ]; then
        local LENGTH="${#PATH_NAME}"
        let LENGTH="${LENGTH}"-1
        PATH_NAME=$(echo "${PATH_NAME:0:${LENGTH}}")
    fi
    
    if [ ! -d $PATH_NAME ]; then
       echo "No Exist Directory $PATH_NAME"
       return 1
    fi
    
    local EXIST_FLAG=0
    for VALUE in ${(s/:/)PATH}
    do
       if [ "$VALUE" = "$PATH_NAME" ]; then
          EXIST_FLAG=1
          break
       fi
    done
    
    if [ "${EXIST_FLAG}" -eq 0 ]; then
        export PATH="${PATH_NAME}:${PATH}"
        echo "Add ${PATH_NAME} in PATH " 1>&2
    elif [ "${EXIST_FLAG}" -eq 1 ]; then
        echo "Already Exist ${PATH_NAME} in PATH " 1>&2
    fi

    unset -v SLASH LENGTH BEFORE_HOME AFTER_HOME PATH_NAME EXIST_FLAG VALUE
    
    return 0
 }
 
 # Add Environment Variable LD_LIBRARY_PATH
 function SetLIBRARY()
 {
    local BEFORE_HOME='$HOME'
    local AFTER_HOME="${HOME}"
    local PATH_NAME=$(echo ${1//"${BEFORE_HOME}"/"${AFTER_HOME}"})

    local SLASH=$(echo ${PATH_NAME: -1:1})
    if [ ${SLASH} = "/" ]; then
        local LENGTH="${#PATH_NAME}"
        let LENGTH=${LENGTH}-1
        PATH_NAME=$(echo ${PATH_NAME:0:${LENGTH}})
    fi

    if [ ! -d "${PATH_NAME}" ]; then
        echo "No Exist Directory ${PATH_NAME}"
        return 1
    fi

    local EXIST_FLAG=0
    for VALUE in ${(s/:/)LD_LIBRARY_PATH}
    do
        if [ "${VALUE}" = "${PATH_NAME}" ]; then
            EXIST_FLAG=1
            break
        fi
    done

    if [ "${EXIST_FLAG}" -eq 0 ]; then
        export LD_LIBRARY_PATH="${PATH_NAME}:${LD_LIBRARY_PATH}"
        echo "Add ${PATH_NAME} in LD_LIBRARY_PATH " 1>&2
    elif [ "${EXIST_FLAG}" -eq 1 ]; then
        echo "Already Exist ${PATH_NAME} in LD_LIBRARY_PATH " 1>&2
    fi

    unset -v SLASH LENGTH BEFORE_HOME AFTER_HOME PATH_NAME EXIST_FLAG VALUE

    return 0
 }
 
 # Change Private IP Address
 function chip()
 {
    if [ ${#} != 1 ]; then
       echo "The argument is wrong." >&2
       return 1
    fi
    
    #sudo ip link set eth0 down
    #sudo nmcli connection down Wired
    sudo nmcli device disconnect eth0
    sudo systemctl stop NetworkManager
    
    sudo sed -i -e "s/^address1=.*/address1="${1}"\/24,192.168.1.1/g" /etc/NetworkManager/system-connections/Wired.nmconnection

    sudo systemctl start NetworkManager
    sudo nmcli device connect eth0
    #sudo nmcli connection up Wired
    #sudo ip link set eth0 up

    return 0
 }
 
 # Start KVM
 function startkvm
 {
   local KVM_STATUS=$(sudo systemctl status libvirtd | \grep "Active:" | \grep -ie "dead")
   if [ -n "KVM_STATUS" ]; then
      sudo systemctl start libvirtd
   fi

   local NETWORK_STATUS=$(LANG=C LANGUAGE=C LC_ALL=C sudo virsh net-info default | \grep -ie "Active:" -ie "Active" | \grep -ie "no")
   if [ -n "$NETWORK_STATUS" ]; then
      sudo virsh net-start default
   fi
   
 #    if [ -f /usr/lib/systemd/system/libvirt-nosleep.service ]; then
 #       local KVM_STATUS=$(sudo systemctl status libvirt-nosleep | grep "Active:" | grep -ie "dead")
 #       if [ -n "KVM_STATUS" ]; then
 #          sudo systemctl start libvirt-nosleep
 #       fi
 #    else
 #       echo "Not exist libvirt-nosleep.service file." 1>&2
 #    fi
 }
 
 # Stop KVM
 function stopkvm
 {
   local NETWORK_STATUS=$(LANG=C LANGUAGE=C LC_ALL=C sudo virsh net-info default | \grep -ie "Active:" -ie "Active" | \grep -ie "yes")
   if [ -n "$NETWORK_STATUS" ]; then
      sudo virsh net-destroy default
   fi

   local KVM_STATUS=$(sudo systemctl status libvirtd | \grep "Active:" | \grep -ie "running")
   if [ -n "KVM_STATUS" ]; then
      sudo systemctl stop libvirtd libvirtd.socket libvirtd-admin.socket libvirtd-ro.socket
   fi

 #    if [ -f /usr/lib/systemd/system/libvirt-nosleep.service ]; then
 #       local KVM_STATUS=$(sudo systemctl status libvirt-nosleep | \grep "Active:" | \grep -ie "Active")
 #       if [ -n "KVM_STATUS" ]; then
 #          sudo systemctl stop libvirt-nosleep
 #       fi
 #    else
 #       echo "Not exist libvirt-nosleep.service file." 1>&2
 #    fi
 }
 
 # Start SSH
 function startssh
 {
    # Get SSH port number
    local PORT=""
    for VALUE in $(sudo \cat /etc/ssh/sshd_config | \grep -E '^Port ' | \cut -d " " -f2-)
    do
        if [ -n $(\echo ${VALUE} | \grep -E '[0-9]') ]; then
            PORT=${VALUE}
            break
        fi
    done
    
    if [ -n $PORT ]; then
        echo "Port Number: ${PORT}"
    else
        echo "Port Number: 22"
    fi
 
    # Start SSH, and then open port Firewalld
    local SSH_STATUS=$(LANG=C LANGUAGE=C LC_ALL=C sudo systemctl status sshd | \grep "Active:" | \grep -ie "dead")
    if [ -n "$SSH_STATUS" ]; then
        sudo systemctl start sshd
 
        echo -n "Open Port Firewalld: "
        if [ -z ${PORT} ]; then
            sudo firewall-cmd --permanent --zone=public --add-service=ssh
        else
            sudo firewall-cmd --permanent --zone=public --add-port="${PORT}"/tcp
        fi
        
        echo -n "Reload Firewalld: "
        sudo firewall-cmd --reload
    fi
    
    if [ -f /usr/lib/systemd/system/inhibit-sleep.service ]; then
        sudo systemctl enable inhibit-sleep.service
    fi
 }
 
 # Stop SSH
 function stopssh
 {
    # Get SSH port number
    local PORT=""
    for VALUE in $(sudo \cat /etc/ssh/sshd_config | \grep -E '^Port ' | \cut -d " " -f2-)
    do
        if [ -n $(\echo ${VALUE} | \grep -E '[0-9]') ]; then
            PORT=${VALUE}
            break
        fi
    done
 
    if [ -n $PORT ]; then
        echo "Port Number: ${PORT}"
    else
        echo "Port Number: 22"
    fi
 
    # Stop SSH, and then, close port Firewalld
    local SSH_STATUS=$(LANG=C LANGUAGE=C LC_ALL=C sudo systemctl status sshd | \grep "Active:" | \grep -ie "running")
    if [ -n "$SSH_STATUS" ]; then
        sudo systemctl stop sshd
 
        echo -n "Close Port Firewalld: "
        if [ -z ${PORT} ]; then
            sudo firewall-cmd --permanent --zone=public --remove-service=ssh
        else
            sudo firewall-cmd --permanent --zone=public --remove-port="${PORT}"/tcp
        fi
 
        echo -n "Reload Firewalld: "
        sudo firewall-cmd --reload
    fi
    
    if [ -f /usr/lib/systemd/system/inhibit-sleep.service ]; then
        sudo systemctl disable inhibit-sleep.service
    fi
 }
 
 # Start Apache2 and MySQL8
 function startlamp()
 {
    local APACHE2_STATUS=$(sudo systemctl status apache2 | \grep "Active:" | \grep -ie "dead")
    if [ -n "APACHE2_STATUS" ]; then
       sudo systemctl start apache2
    fi
 
    local MYSQL8_STATUS=$(sudo systemctl status mysql | \grep "Active:" | \grep -ie "dead")
    if [ -n "MYSQL8_STATUS" ]; then
       sudo systemctl start mysql
    fi
 }
 
 # Stop Apache2 and MySQL8
 function stoplamp()
 {
    local APACHE2_STATUS=$(sudo systemctl status apache2 | \grep "Active:" | \grep -ie "running")
    if [ -n "APACHE2_STATUS" ]; then
       sudo systemctl stop apache2
    fi
 
    local MYSQL8_STATUS=$(sudo systemctl status mysql | \grep "Active:" | \grep -ie "running")
    if [ -n "MYSQL8_STATUS" ]; then
       sudo systemctl stop mysql
    fi
 }