20200223のLinuxに関する記事は12件です。

CentOSでsarコマンドを使えるようにする(sysstatをインストール)

1. 環境

  • OS:CentOS Linux release 7.7.1908 (Core)
[root@CENTOS7 ~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[root@CENTOS7 ~]#

2. yum-utilsをインストール

sarコマンドには関係ありませんが、パッケージに含まれるファイル等を調べるrepoqueryコマンドを使用するため、yum-utilsをインストールします。
yum-utilsをインストールしなくても、sysstatをインストールすれば、sarコマンドを使用できます。

yum install -y yum-utils

実行結果
[root@CENTOS7 ~]# yum install -y yum-utils
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ yum-utils.noarch 0:1.1.31-52.el7 を インストール
--> 依存性の処理をしています: python-kitchen のパッケージ: yum-utils-1.1.31-52.el7.noarch
--> 依存性の処理をしています: libxml2-python のパッケージ: yum-utils-1.1.31-52.el7.noarch
--> トランザクションの確認を実行しています。
---> パッケージ libxml2-python.x86_64 0:2.9.1-6.el7_2.3 を インストール
---> パッケージ python-kitchen.noarch 0:1.1.1-5.el7 を インストール
--> 依存性の処理をしています: python-chardet のパッケージ: python-kitchen-1.1.1-5.el7.noarch
--> トランザクションの確認を実行しています。
---> パッケージ python-chardet.noarch 0:2.2.1-3.el7 を インストール
--> 依存性解決を終了しました。

依存性を解決しました

================================================================================
 Package               アーキテクチャー
                                     バージョン               リポジトリー
                                                                           容量
================================================================================
インストール中:
 yum-utils             noarch        1.1.31-52.el7            base        121 k
依存性関連でのインストールをします:
 libxml2-python        x86_64        2.9.1-6.el7_2.3          base        247 k
 python-chardet        noarch        2.2.1-3.el7              base        227 k
 python-kitchen        noarch        1.1.1-5.el7              base        267 k

トランザクションの要約
================================================================================
インストール  1 パッケージ (+3 個の依存関係のパッケージ)

総ダウンロード容量: 862 k
インストール容量: 4.3 M
Downloading packages:
(1/4): python-chardet-2.2.1-3.el7.noarch.rpm               | 227 kB   00:01
(2/4): yum-utils-1.1.31-52.el7.noarch.rpm                  | 121 kB   00:01
(3/4): python-kitchen-1.1.1-5.el7.noarch.rpm               | 267 kB   00:02
(4/4): libxml2-python-2.9.1-6.el7_2.3.x86_64.rpm           | 247 kB   00:02
--------------------------------------------------------------------------------
合計                                               326 kB/s | 862 kB  00:02
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  インストール中          : python-chardet-2.2.1-3.el7.noarch               1/4
  インストール中          : python-kitchen-1.1.1-5.el7.noarch               2/4
  インストール中          : libxml2-python-2.9.1-6.el7_2.3.x86_64           3/4
  インストール中          : yum-utils-1.1.31-52.el7.noarch                  4/4
  検証中                  : python-kitchen-1.1.1-5.el7.noarch               1/4
  検証中                  : yum-utils-1.1.31-52.el7.noarch                  2/4
  検証中                  : libxml2-python-2.9.1-6.el7_2.3.x86_64           3/4
  検証中                  : python-chardet-2.2.1-3.el7.noarch               4/4

インストール:
  yum-utils.noarch 0:1.1.31-52.el7

依存性関連をインストールしました:
  libxml2-python.x86_64 0:2.9.1-6.el7_2.3  python-chardet.noarch 0:2.2.1-3.el7
  python-kitchen.noarch 0:1.1.1-5.el7

完了しました!
[root@CENTOS7 ~]#

3. sarコマンドを提供しているパッケージを検索する

以下のコマンドでsarコマンドを提供しているパッケージを検索します。
yum provides sar

実行結果
[root@CENTOS7 ~]# yum provides sar
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
sysstat-10.1.5-18.el7.x86_64 : Collection of performance monitoring tools for
                             : Linux
リポジトリー        : base
一致          :
ファイル名    : /usr/bin/sar



[root@CENTOS7 ~]#

sysstat-10.1.5-18.el7.x86_64sarコマンドが存在することがわかりました。

4. sysstatパッケージをインストール

以下のコマンドでsysstatパッケージをインストールします。

yum install -y sysstat

実行結果
[root@CENTOS7 ~]# yum install -y sysstat
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> パッケージ sysstat.x86_64 0:10.1.5-18.el7 を インストール
--> 依存性の処理をしています: libsensors.so.4()(64bit) のパッケージ: sysstat-10.1.5-18.el7.x86_64
--> トランザクションの確認を実行しています。
---> パッケージ lm_sensors-libs.x86_64 0:3.4.0-8.20160601gitf9185e5.el7 を イン ストール
--> 依存性解決を終了しました。

依存性を解決しました

================================================================================
 Package            アーキテクチャー
                              バージョン                          リポジトリー
                                                                           容量
================================================================================
インストール中:
 sysstat            x86_64    10.1.5-18.el7                       base    315 k
依存性関連でのインストールをします:
 lm_sensors-libs    x86_64    3.4.0-8.20160601gitf9185e5.el7      base     42 k

トランザクションの要約
================================================================================
インストール  1 パッケージ (+1 個の依存関係のパッケージ)

総ダウンロード容量: 357 k
インストール容量: 1.2 M
Downloading packages:
(1/2): sysstat-10.1.5-18.el7.x86_64.rpm                    | 315 kB   00:00
(2/2): lm_sensors-libs-3.4.0-8.20160601gitf9185e5.el7.x86_ |  42 kB   00:01
--------------------------------------------------------------------------------
合計                                               254 kB/s | 357 kB  00:01
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  インストール中          : lm_sensors-libs-3.4.0-8.20160601gitf9185e5.el   1/2
  インストール中          : sysstat-10.1.5-18.el7.x86_64                    2/2
  検証中                  : lm_sensors-libs-3.4.0-8.20160601gitf9185e5.el   1/2
  検証中                  : sysstat-10.1.5-18.el7.x86_64                    2/2

インストール:
  sysstat.x86_64 0:10.1.5-18.el7

依存性関連をインストールしました:
  lm_sensors-libs.x86_64 0:3.4.0-8.20160601gitf9185e5.el7

完了しました!
[root@CENTOS7 ~]#

5. sysstatパッケージに含まれるファイルを確認

以下のコマンドでsysstatパッケージに含まれるファイルを確認します。
repoqueryコマンドを使用するにはyum-utilsパッケージのインストールが必要です。)

repoquery --list sysstat

実行結果
[root@CENTOS7 ~]# repoquery sysstat
sysstat-0:10.1.5-18.el7.x86_64
[root@CENTOS7 ~]# repoquery --list sysstat
/etc/cron.d/sysstat
/etc/sysconfig/sysstat
/etc/sysconfig/sysstat.ioconf
/usr/bin/cifsiostat
/usr/bin/iostat
/usr/bin/mpstat
/usr/bin/nfsiostat-sysstat
/usr/bin/pidstat
/usr/bin/sadf
/usr/bin/sar
/usr/bin/tapestat
/usr/lib/systemd/system/sysstat.service
/usr/lib64/sa
/usr/lib64/sa/sa1
/usr/lib64/sa/sa2
/usr/lib64/sa/sadc
/usr/share/doc/sysstat-10.1.5
/usr/share/doc/sysstat-10.1.5/CHANGES
/usr/share/doc/sysstat-10.1.5/COPYING
/usr/share/doc/sysstat-10.1.5/CREDITS
/usr/share/doc/sysstat-10.1.5/FAQ
/usr/share/doc/sysstat-10.1.5/README
/usr/share/doc/sysstat-10.1.5/sysstat-10.1.5.lsm
/usr/share/locale/af/LC_MESSAGES/sysstat.mo
/usr/share/locale/cs/LC_MESSAGES/sysstat.mo
/usr/share/locale/da/LC_MESSAGES/sysstat.mo
/usr/share/locale/de/LC_MESSAGES/sysstat.mo
/usr/share/locale/eo/LC_MESSAGES/sysstat.mo
/usr/share/locale/es/LC_MESSAGES/sysstat.mo
/usr/share/locale/eu/LC_MESSAGES/sysstat.mo
/usr/share/locale/fi/LC_MESSAGES/sysstat.mo
/usr/share/locale/fr/LC_MESSAGES/sysstat.mo
/usr/share/locale/hr/LC_MESSAGES/sysstat.mo
/usr/share/locale/id/LC_MESSAGES/sysstat.mo
/usr/share/locale/it/LC_MESSAGES/sysstat.mo
/usr/share/locale/ja/LC_MESSAGES/sysstat.mo
/usr/share/locale/ky/LC_MESSAGES/sysstat.mo
/usr/share/locale/lv/LC_MESSAGES/sysstat.mo
/usr/share/locale/mt/LC_MESSAGES/sysstat.mo
/usr/share/locale/nb/LC_MESSAGES/sysstat.mo
/usr/share/locale/nl/LC_MESSAGES/sysstat.mo
/usr/share/locale/nn/LC_MESSAGES/sysstat.mo
/usr/share/locale/pl/LC_MESSAGES/sysstat.mo
/usr/share/locale/pt/LC_MESSAGES/sysstat.mo
/usr/share/locale/pt_BR/LC_MESSAGES/sysstat.mo
/usr/share/locale/ro/LC_MESSAGES/sysstat.mo
/usr/share/locale/ru/LC_MESSAGES/sysstat.mo
/usr/share/locale/sk/LC_MESSAGES/sysstat.mo
/usr/share/locale/sr/LC_MESSAGES/sysstat.mo
/usr/share/locale/sv/LC_MESSAGES/sysstat.mo
/usr/share/locale/uk/LC_MESSAGES/sysstat.mo
/usr/share/locale/vi/LC_MESSAGES/sysstat.mo
/usr/share/locale/zh_CN/LC_MESSAGES/sysstat.mo
/usr/share/locale/zh_TW/LC_MESSAGES/sysstat.mo
/usr/share/man/man1/cifsiostat.1.gz
/usr/share/man/man1/iostat.1.gz
/usr/share/man/man1/mpstat.1.gz
/usr/share/man/man1/nfsiostat-sysstat.1.gz
/usr/share/man/man1/pidstat.1.gz
/usr/share/man/man1/sadf.1.gz
/usr/share/man/man1/sar.1.gz
/usr/share/man/man1/tapestat.1.gz
/usr/share/man/man5/sysstat.5.gz
/usr/share/man/man8/sa1.8.gz
/usr/share/man/man8/sa2.8.gz
/usr/share/man/man8/sadc.8.gz
/var/log/sa
[root@CENTOS7 ~]#

6. sysstatパッケージに含まれるファイルの中からコマンドのみを確認

以下のコマンドでsysstatパッケージに含まれるファイルの中からコマンドのみを確認します。
repoqueryコマンドを使用するにはyum-utilsパッケージのインストールが必要です。)

repoquery --list sysstat | grep bin

実行結果
[root@CENTOS7 ~]# repoquery --list sysstat | grep bin
/usr/bin/cifsiostat
/usr/bin/iostat
/usr/bin/mpstat
/usr/bin/nfsiostat-sysstat
/usr/bin/pidstat
/usr/bin/sadf
/usr/bin/sar
/usr/bin/tapestat
[root@CENTOS7 ~]#

sarコマンドの他にiostat等のコマンドも存在することがわかります。


以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linuxのmanコマンドの出力結果をファイルに出力する方法

Linuxのmanコマンドの出力結果をファイルに出力する方法を紹介します。

環境

  • OS:CentOS Linux release 7.7.1908
[root@CENTOS7 ~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[root@CENTOS7 ~]#

manコマンドの出力結果をファイルに出力(colコマンドで制御文字を除去)

man コマンド | col -bfx > ファイル

[root@CENTOS7 ~]# man top | col -bfx > top.txt
[root@CENTOS7 ~]#

CentOS7では

CentOS7では

man top | col -bfx > top.txt
の結果と
man top > top2.txt
の結果は同じとなりました。

[root@CENTOS7 ~]# man top | col -bfx > top.txt
[root@CENTOS7 ~]# man top > top2.txt
[root@CENTOS7 ~]# diff top.txt top2.txt
[root@CENTOS7 ~]#

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LinuxのBashでディレクトリにあるファイルのフルパス(絶対パス)を表示する

はじめに

初めての投稿なので至らぬことがあるかもしれませんが、どうかよろしくお願いいたします。おかしな点や改善点などがあれば遠慮なくコメントをください。

概要

この記事は一般的Linux環境(ここではdebian系を想定)のBashを使った、ディレクトリにあるファイルのフルパス(絶対パス)を表示するコマンド(スクリプト)を紹介します。

動機

Google Compute Engine(GCE)のコンソールでファイルをダウンロードする際にファイルのフルパスが必要になったために作りました。

仕様

コマンド名

lfでは、"ls"で表示されるファイルと同じファイルを同じ順でフルパスで表示します。
lfaでは、"ls -a"で表示されるファイルと同じファイルを同じ順でフルパスで表示します。つまり、ドット付きファイルも表示されます。
lftでは、"ls -t"で表示されるファイルと同じファイルを同じ順でフルパスで表示します。つまり、更新時刻が新しい順に表示されます。

入力仕様

入力としてコマンド引数に、ファイル名(ファイルパス)やディレクトリ名(ディレクトリパス)を複数指定できるようにします。相対パス、絶対パスどちらでも構いません。ディレクトリが含まれていない場合はカレントディレクトリにあると想定します。PATH変数等から検索はしません。
グロブ (glob) はコマンド側では制御しません。

出力仕様

入力されたファイル名やディレクトリ名の順に処理を行い、ディレクトリならばそのディレクトリにあるすべてのファイルのフルパスを標準出力に出力します。ディレクトリではない場合はファイルのフルパスを標準出力に出力します。

エラー処理

引数に指定されたパスが存在しない場合はエラーを出力します。

実装

実装は ~/.bashrc の最後に記述しました。
readlinkが使えない場合はコメントにされている次の行を使用してください。
"--color=auto"は不要だと思いますので消しても良いです。

~/.bashrc
function _lsfp () 
{ 
    local dir file;
    if [[ -d $1 ]]; then
        dir=$(cd "$1";pwd);
        ls --color=auto -1 $2 "$1" | while read file; do
            echo "$dir/$file";
        done;
    elif [[ -e $1 ]]; then
         readlink -f "$1"
#         echo "$(cd $(dirname "$1");pwd)/${1##*/}";
    else
        echo "'$1' is not found." >&2;
    fi
}

function lsfp () 
{ 
    local arg;
    [[ $# -eq 0 ]] && _lsfp "$(pwd)" || for arg in "$@";
    do
        _lsfp "$arg";
    done
}

function lsfpa () 
{ 
    local arg;
    [[ $# -eq 0 ]] && _lsfp "$(pwd)" -a || for arg in "$@";
    do
        _lsfp "$arg" -a;
    done
}

function lsfpt () 
{ 
    local arg;
    [[ $# -eq 0 ]] && _lsfp "$(pwd)" -t || for arg in "$@";
    do
        _lsfp "$arg" -t;
    done
}

alias lf='lsfp'
alias lfa='lsfpa'
alias lft='lsfpt'

試験

$ cd ~/
$ source ./.bashrc
$ lf
$ lfa
$ lft
$ lf ~/

あとがき

Bashはとても便利ですね。これから色々使っていこうと思います。最後まで読んでくれてありがとうございます。

追記

短くしてサイズ順(大きい順)で表示するlfsも追加してみました。関数名等が変わっています。

~/.bashrc
function __lsfp () 
{ 
    local dir file;
    if [[ -d $1 ]]; then
        dir=$(cd "$1";pwd);
        ls --color=auto -1 $2 "$1" | while read ent; do
            echo "$dir/$ent";
        done;
    elif [[ -e $1 ]]; then
         readlink -f "$1"
#         echo "$(cd $(dirname "$1");pwd)/${1##*/}";
    else
        echo "'$1' is not found." >&2;
    fi
}

function _lsfp () 
{ 
    local opt arg;
    [[ $1 =~ ^-[A-Za-z\-]$ ]] && { opt=$1; shift; }
    [[ $# -eq 0 ]] && __lsfp "$(pwd)" $opt || for arg in "$@";
    do
        __lsfp "$arg" $opt;
    done
}

alias lf='_lsfp --'
alias lfa='_lsfp -a'
alias lft='_lsfp -t'
alias lfs='_lsfp -S' # サイズ順
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

階層構造をもつTODOリストの作り方

はじめに

以前、階層構造をもつTODOリストをWebアプリケーションとして実装したので、その知見を共有します。

実際に作成したTODOリスト(OSSとして公開)


機能一覧

  • メモの新規作成
  • メモの編集(編集前の内容がテキストボックスに入力されている)
  • メモの削除
  • メモの追加(メモAの下にメモBを紐付け)
  • メモを一つ上の階層に移動
  • メモの一括削除
  • 新規作成や編集時のテキストボックスを、ボックス外の任意の場所をクリックすることで非表示(UX)
  • MemoモードとTaskモードの切り替え
  • (Taskモードのみ) メモ横のチェックボックスにチェックを入れると、非同期で打ち消し線を表示

解説

技術スタックは、Docker Compose、Java、PostgreSQLがメインです。

内部では基本的にCRUDしか行っておらず、DB側で再帰的なデータを保存しています。

Docker Compose

portsを定義して、ホストとゲストのポートをマッピングしています。

サービス名tomcatpostgresでお互い接続は可能なはずですが、ipv4も固定していました(理由は失念してしまいました)。

version: "3.7"
services:
  tomcat:
# When building from source code, uncomment following build
# and remove local image. e.g.) docker rmi resotto/tomcat:1.0
#    build: ap/
    image: resotto/tomcat:1.0
    container_name: tomcat
    tty: true
    ports:
     - "8888:8080"
    networks:
      app_net:
        ipv4_address: 172.16.1.3

  postgres:
# When building from source code, uncomment following build
# and remove local image. e.g.) docker rmi resotto/postgres:1.0
#    build: db/
    image: resotto/postgres:1.0
    container_name: postgres
    tty: true
    networks:
      app_net:
        ipv4_address: 172.16.1.2

networks:
  app_net:
    ipam:
      driver: default
      config:
       - subnet: "172.16.1.0/24"

DB

使い捨てアプリのため、postgresサービスのDockerfileから呼び出すstartup.sh内にスキーマを定義していました。

要素テーブルとその関連テーブルの2つを定義しました。

要素テーブルは(恥ずかしいのですが)テーブル名が残念なのと、typeカラムは数字で種類の情報を保持しているため、アンチパターンです。

element_typesテーブルを定義し、そちらへの外部キー制約をつけるのが良いです。

関連テーブルは、要素テーブルの主キーidの親と子で複合主キーになっています。

#!/bin/bash
service postgresql-9.6 start
psql -U postgres -c "create role uranus superuser login"
createdb -U postgres -O uranus uranusdb
psql -U uranus uranusdb -c \
"create table mst_element ( \
  id serial PRIMARY KEY, \
  type integer, \
  title text, \
  is_checked boolean, \
  is_root boolean, \
  create_date date, \
  update_date date \
);"

psql -U uranus uranusdb -c \
"create table mst_relation ( \
  parent_id integer, \
  child_id integer, \
  PRIMARY KEY (parent_id, child_id) \
);"

/bin/bash

フロントエンド

(画面の実装は採用する技術次第ですが)再帰的に表示する部分を独立して実装しました。

<!-- index.jsp -->
<!DOCTYPE html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Uranus</title>
        <link rel="stylesheet" href="${f:url('/css/index.css')}">
        <noscript>
            <link rel="stylesheet" href="${f:url('/css/noscript.css')}">
        </noscript>
    </head>
    <body>
        <!-- header -->
        <h1>
            <c:choose>
                <c:when test="${mode eq 0}">
                    [ Memo ] /
                    <s:link href="task">Task</s:link>
                </c:when>
                <c:otherwise>
                    <s:link href="memo">Memo</s:link>
                    / [ Task ]
                </c:otherwise>
            </c:choose>
        </h1>
        <p>
            <!-- create button -->
            <input type="button" onclick="toggleCreateMode()" value="new" class="btn createButton">
            <!-- clear section -->
            <div id="clearButton">
                <s:form>
                    <input type="submit" name="clear" value="clear" class="btn">
                    <input type="hidden" name="mode" value="${mode}">
                </s:form>
            </div>
        </p>
        <!-- create block -->
        <div id="createBlock">
            <s:form>
                <textarea name="inputText" rows="3" cols="30"></textarea>
                <input type="submit" name="create" value="create" class="btn">
                <input type="hidden" name="mode" value="${mode}">
            </s:form>
        </div>
        <!-- main contents -->
        <ul>
            <c:forEach var="elm" items="${list}" varStatus="parentStatus">
                <c:if test="${mode eq 1}">
                    <c:if test="${elm.updateDate.toString() != date}">
                        <p>
                            <h2>
                                ${elm.updateDate}
                            </h2>
                            <c:set var="date" value="${elm.updateDate.toString()}" scope="request"></c:set>
                        </p>
                    </c:if>
                </c:if>
                <c:set var="child" value="${elm}" scope="request"></c:set>
                <c:import url="element.jsp"></c:import>
                <br>
            </c:forEach>
        </ul>
        <script type="text/javascript" src="${f:url('/js/index.js')}"></script>
    </body>
</html>
<!-- element.jsp -->
<li>
    <c:if test="${mode eq 1}">
        <input type="checkbox" id="checkbox_${child.id}" onclick="toggleCheckbox(this)" ${child.isChecked ? "checked" : ""}>
    </c:if>
    <p>
        <c:if test="${child.isChecked}"><del></c:if>
            ${child.title}
        <c:if test="${child.isChecked}"></del></c:if>
        &nbsp;
    </p>
    <p>
        <input type="button" onclick="toggleAddMode(this)" value="+" class="btn addButton">
    </p>
    <p>
        <input type="button" onclick="toggleEditMode(this)" value="edit" class="btn editButton">
    </p>
    <c:if test="${child.isRoot == false}">
        <s:form>
            <input type="submit" name="up" value="↑" class="btn">
            <input type="hidden" name="targetId" value="${child.id}">
            <input type="hidden" name="mode" value="${mode}">
        </s:form>
    </c:if>
    <s:form>
        <input type="submit" name="remove" value="-" class="btn">
        <input type="hidden" name="targetId" value="${child.id}">
        <input type="hidden" name="mode" value="${mode}">
    </s:form>
    <div class="addBlock">
        <s:form>
            <textarea name="addText" rows="3" cols="30"></textarea>
            <input type="submit" name="add" value="add" class="btn">
            <input type="hidden" name="targetId" value="${child.id}">
            <input type="hidden" name="mode" value="${mode}">
        </s:form>
    </div>
    <div class="editBlock">
        <s:form>
            <textarea name="editText" rows="3" cols="30">${child.title}</textarea>
            <input type="submit" name="update" value="update" class="btn">
            <input type="hidden" name="targetId" value="${child.id}">
            <input type="hidden" name="mode" value="${mode}">
        </s:form>
    </div>
    <ul>
        <c:if test="${child.children != null}">
            <c:forEach var="child" items="${child.children}" varStatus="childStatus">
                <c:set var="child" value="${child}" scope="request"></c:set>
                <c:import url="element.jsp"></c:import>
            </c:forEach>
        </c:if>
    </ul>
</li>

UIUX

(変数を定数っぽく書いたりと迷走してますが)非同期で打ち消し線を入れたり、他の領域をクリックすることによる非表示を実装しています。

// index.js
let createMode = false;
let addMode = false;
let editMode = false;

const toggleCreateMode = () => {
    createMode = !createMode;
    const CREATE_BLOCK = document.getElementById("createBlock");
    if (createMode) {
        CREATE_BLOCK.style.display = "block";
    } else {
        CREATE_BLOCK.style.display = "none";
    }
}

const toggleAddMode = (elm) => {
    const ID = elm.id.split("_")[1];
    addMode = !addMode;
    const ADD_BLOCK = document.getElementById("addBlock_" + ID);
    if (addMode) {
        ADD_BLOCK.style.display = "block";
    } else {
        ADD_BLOCK.style.display = "none";
    }
};

const toggleEditMode = (elm) => {
    const ID = elm.id.split("_")[1];
    editMode = !editMode;
    const EDIT_BLOCK = document.getElementById("editBlock_" + ID);
    if (editMode) {
        EDIT_BLOCK.style.display = "block";
    } else {
        EDIT_BLOCK.style.display = "none";
    }
};

const toggleCheckbox = (elm) => {
    const XHR = new XMLHttpRequest();
    const FD = new FormData();
    const ID = elm.id.split("_")[1];
    const URL = "http://" + location.host
        + location.pathname.match(/\/.+\//) + "toggleCheck";
    FD.append("targetId", ID);
    XHR.open("POST", URL);
    XHR.send(FD);
}

const setEventListener = (selector) => {
    const ELM = document.getElementById(selector);
    if (selector == "createBlock") {
        document.addEventListener('click', function(e) {
            if (!e.target.closest(".createButton")
                    && !e.target.closest("#createBlock")) {
                createMode = false;
                ELM.style.display = "none";
            }
        }, false)
        return;
    }
    const CLASSNAME = selector.split("_")[0];
    if (CLASSNAME == "addBlock") {
        document.addEventListener('click', function(e) {
            if (!e.target.closest(".addButton")
                    && !e.target.closest("#" + selector)) {
                addMode = false;
                ELM.style.display = "none";
            }
        }, false)
    } else {
        document.addEventListener('click', function(e) {
            if (!e.target.closest(".editButton")
                    && !e.target.closest("#" + selector)) {
                editMode = false;
                ELM.style.display = "none";
            }
        }, false)
    }
}

const setId = (str, settingListener) => {
    const LIST = document.getElementsByClassName(str);
    for (let i = 0; i < LIST.length; i++) {
        const ID = str + "_" + i;
        LIST[i].setAttribute("id", ID);
        if (settingListener) {
            setEventListener(ID);
        }
    }
}

const setIndex = () => {
    setEventListener("createBlock");
    setId("addButton", false);
    setId("addBlock", true);
    setId("editButton", false);
    setId("editBlock", true);
}

window.onload = function() {
    setIndex();
}

バックエンド

(Webフレームワークにもよりますが)リクエストを受け取って必要な(ロジック)サービスを呼び出して処理を行っていました。

要素の入れ替えロジックの実装が大変でした。

package com.uranus.service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.dbflute.cbean.result.ListResultBean;
import org.dbflute.exception.EntityAlreadyDeletedException;
import org.dbflute.optional.OptionalEntity;

import com.uranus.dbflute.exbhv.MstElementBhv;
import com.uranus.dbflute.exbhv.MstRelationBhv;
import com.uranus.dbflute.exentity.MstElement;
import com.uranus.dbflute.exentity.MstRelation;
import com.uranus.dto.ElementDto;
import com.uranus.dxo.ElementDxo;
import com.uranus.util.MstElementDateComparator;
import com.uranus.util.MstElementIdComparator;
import com.uranus.util.StringUtil;
import com.uranus.util.Type;

public class IndexService {

    @Resource
    protected MstElementBhv mstElementBhv;

    @Resource
    protected MstRelationBhv mstRelationBhv;

    /**
     * Parent ElementDto
     */
    private static ElementDto parent;

    /**
     * Log4j logger
     */
    public Logger logger = Logger.getLogger(IndexService.class);

    // -------------------------- public methods --------------------------

    /**
     * Setup ElementDto and return it.
     * @param  text title
     * @return      assembled ElementDto
     */
    public ElementDto assembleElementDto(String text, String mode) {
        ElementDto dto = new ElementDto();
        dto.type = Integer.parseInt(mode);
        dto.title = StringUtil.sanitize(text);
        LocalDate now = LocalDate.now();
        dto.createDate = now;
        dto.updateDate = now;
        return dto;
    }

    /**
     * Get root elements and their children (recursively) from database.
     * @param  type element type
     * @return      contents list if exists, otherwise {@code null}
     */
    public List<ElementDto> getList(int type) {
        List<Integer> rootIdList = getRootElementsId(type);
        if (rootIdList.size() == 0) return null;
        Map<Integer, ElementDto> elmMap = createElementMap(rootIdList);
        ListResultBean<MstRelation> rootRels = getRootRelation(rootIdList);
        rootRels.forEach(rel -> {
            ElementDto parentDto = getParent(elmMap.get(rel.getParentId()));
            setChildren(parentDto, rel.getChildId());
        });
        return createSortedList(elmMap, type);
    }

    /**
     * Create new element.
     * @param dto target ElementDto
     */
    public void createElement(ElementDto dto) {
        insertElement(dto, true);
    }

    /**
     * Add element.
     * @param parentId parent element id
     * @param childDto child ElementDto
     */
    public void addElement(int parentId, ElementDto childDto) {
        MstElement element = insertElement(childDto, false);
        insertRelation(parentId, element.getId());
    }

    /**
     * Update element.
     * @param targetId target element id
     * @param text     element text
     */
    public void updateElementText(int targetId, String text) {
        ElementDto dto = getElementDtoById(targetId);
        dto.title = text;
        dto.updateDate = LocalDate.now();
        MstElement element = ElementDxo.toElementEntity(dto);
        updateElement(element);
    }

    /**
     * Remove element and its relation (recursively) from database.
     * @param id target element id
     */
    public void removeElement(int id) {
        MstElement element = getElementEntityById(id);
        if (element == null) return;
        MstRelation upwardRel = getUpwardRelation(element.getId());
        if (upwardRel != null) deleteRelation(upwardRel);
        removeDownwardContents(element.getId());
    }

    /**
     * Toggle element's isChecked property.
     * @param id target element id
     */
    public void toggleElementCheck(int id) {
        MstElement element = getElementEntityById(id);
        if (element == null) return;
        boolean checked = element.getIsChecked();
        element.setIsChecked(!checked);
        updateElement(element);
    }

    /**
     * Exchange elements relation.
     * @param childId target element id to be promoted
     */
    public void exchangeElements(int childId) {
        if (getElementDtoById(childId).isRoot) return;
        int parentId = getUpwardRelation(childId).getParentId();
        Integer ancestorId = getAncestorId(parentId);
        rearrangeAncestorRelation(ancestorId, parentId, childId);
        ListResultBean<MstRelation> childRels = getRelationByParentId(childId);
        ListResultBean<MstRelation> parentRels = getRelationByParentId(parentId);
        rearrangeChildRelation(parentId, childId, childRels);
        rearrangeParentRelation(parentId, childId, parentRels);
        toggleIsRootProperty(childId, parentId);
    }

    /**
     * Delete all elements and relations with type.
     * @param type contents type
     */
    public void clear(int type) {
        List<Integer> rootElmsIdList = getRootElementsId(type);
        rootElmsIdList.forEach(rootElm -> {
            removeDownwardContents(rootElm);
        });
    }

    // -------------------------- private methods --------------------------

    /**
     * Get ancestor element id.
     * @param  parentId parent element id
     * @return          ancestor element id if exists, otherwise {@code null}
     */
    private Integer getAncestorId(int parentId) {
        MstRelation rel = getUpwardRelation(parentId);
        if (rel != null) return rel.getParentId();
        return null;
    }

    /**
     * Rearrange relation between ancestor element, parent element, and target
     * element.
     * @param ancestorId ancestor element id
     * @param parentId   parent element id
     * @param targetId   target element id to be promoted
     */
    private void rearrangeAncestorRelation(Integer ancestorId, int parentId, int targetId) {
        if (ancestorId != null) {
            deleteRelation(ancestorId, parentId);
            insertRelation(ancestorId, targetId);
        }
    }

    /**
     * Rearrange relation between parent element and target element.
     * @param parentId   parent element id
     * @param targetId   target element id to be promoted
     * @param parentRels parent element's downward relation
     */
    private void rearrangeParentRelation(int parentId, int targetId, ListResultBean<MstRelation> parentRels) {
        removeRelations(parentId, parentRels);
        createRelations(targetId, parentRels);
        insertRelation(targetId, parentId);
    }

    /**
     * Rearrange target element downward relation.
     * @param parentId  parent element id
     * @param targetId  target element id to be promoted
     * @param childRels target element's downward relation
     */
    private void rearrangeChildRelation(int parentId, int targetId, ListResultBean<MstRelation> childRels) {
        if (childRels.size() > 0) {
            removeRelations(targetId, childRels);
            createRelations(parentId, childRels);
        }
    }

    /**
     * Get downward relation by parent id.
     * @param  parentId parent element id
     * @return          relation list
     */
    private ListResultBean<MstRelation> getRelationByParentId(int parentId) {
        ListResultBean<MstRelation> rels = mstRelationBhv.selectList(cb -> {
            cb.query().setParentId_Equal(parentId);
        });
        return rels;
    }

    /**
     * Toggle element is_root property.
     * @param newParentId element id to be promoted
     * @param oldParentId element id to be demoted
     */
    private void toggleIsRootProperty(int newParentId, int oldParentId) {
        MstElement oldParent = getElementEntityById(oldParentId);
        if (oldParent.getIsRoot()) {
            oldParent.setIsRoot(false);
            updateElement(oldParent);
            MstElement newParent = getElementEntityById(newParentId);
            newParent.setIsRoot(true);
            updateElement(newParent);
        }
    }

    /**
     * Create relation with parentId and relation list's childId.
     * @param parentId parent element id
     * @param rels     relation list
     */
    private void createRelations(int parentId, ListResultBean<MstRelation> rels) {
        rels.forEach(rel -> {
            if (parentId != rel.getChildId()) {
                insertRelation(parentId, rel.getChildId());
            }
        });
    }

    /**
     * Remove relation with parentId and relation list's childId.
     * @param parentId
     * @param rels
     */
    private void removeRelations(int parentId, ListResultBean<MstRelation> rels) {
        rels.forEach(rel -> {
            deleteRelation(parentId, rel.getChildId());
        });
    }

    /**
     * Create map from root elements id.
     * @param  rootIdList root elements id
     * @return            map key:element id, value:ElementDto
     */
    private Map<Integer, ElementDto> createElementMap(List<Integer> rootIdList) {
        Map<Integer, ElementDto> elmMap = new HashMap<>();
        ListResultBean<MstElement> rootElms = getRootElement(rootIdList);
        rootElms.forEach(rootElm -> {
            elmMap.put(rootElm.getId(), ElementDxo.toElementDto(rootElm));
        });
        return elmMap;
    }

    /**
     * Create list from map.
     * @param  map  key:id, value:ElementDto
     * @param  type contents type
     * @return      ElementDto list
     */
    private List<ElementDto> createSortedList(Map<Integer, ElementDto> map, int type) {
        List<ElementDto> list = new ArrayList<>(map.values());
        if (type == Type.MEMO.getType()) {
            list.sort(new MstElementIdComparator());
        } else {
            list.sort(new MstElementDateComparator());
        }
        return list;
    }

    /**
     * Get root elements by root elements id.
     * @param  rootIdList root elements id list
     * @return            root elements list
     */
    private ListResultBean<MstElement> getRootElement(List<Integer> rootIdList) {
        ListResultBean<MstElement> rootElms = mstElementBhv.selectList(cb -> {
            cb.query().setId_InScope(rootIdList);
            cb.query().addOrderBy_Id_Asc();
        });
        return rootElms;
    }

    /**
     * Get root relation by root elements id.
     * @param  rootIdList root elements id list
     * @return            root relation list
     */
    private ListResultBean<MstRelation> getRootRelation(List<Integer> rootIdList) {
        ListResultBean<MstRelation> rootRels = mstRelationBhv.selectList(cb -> {
            cb.query().setParentId_InScope(rootIdList);
            cb.query().addOrderBy_ParentId_Asc();
        });
        logger.info("    Root relation list: " + rootRels);
        return rootRels;
    }

    /**
     * Delete downward relation and its element recursively from database.
     * @param parentId parent element id
     */
    private void removeDownwardContents(int parentId) {
        List<MstRelation> downwardRels = getAllRelation(parentId);
        downwardRels.forEach(rel -> {
            removeDownwardContents(rel.getChildId());
            deleteRelation(parentId, rel.getChildId());
        });
        MstElement elm = getElementEntityById(parentId);
        deleteElement(elm);
    }

    /**
     * Update element.
     * @param elm element entity
     */
    private void updateElement(MstElement elm) {
        mstElementBhv.update(elm);
        logger.info("    Element updated: " + elm);
    }

    /**
     * Delete element from database by element entity.
     * @param  elm element entity
     * @return     element entity after deletion.
     */
    private MstElement deleteElement(MstElement elm) {
        mstElementBhv.delete(elm);
        logger.info("    Element deleted: " + elm);
        return elm;
    }

    /**
     * Delete relation from database by parentId and childId.
     * @param  parentId parent element id.
     * @param  childId  child element id.
     * @return          relation entity after deletion.
     */
    private MstRelation deleteRelation(int parentId, int childId) {
        MstRelation rel = new MstRelation();
        rel.setParentId(parentId);
        rel.setChildId(childId);
        return deleteRelation(rel);
    }

    /**
     * Delete relation from database by relation entity.
     * @param  rel relation entity
     * @return     relation entity after deletion.
     */
    private MstRelation deleteRelation(MstRelation rel) {
        try {
            mstRelationBhv.delete(rel);
        } catch (EntityAlreadyDeletedException e) {}
        logger.info("    Relation deleted: " + rel);
        return rel;
    }

    /**
     * Get all relation by id.
     * @param  parentId parent element id
     * @return          relation entity list
     */
    private ListResultBean<MstRelation> getAllRelation(int parentId) {
        ListResultBean<MstRelation> rels = mstRelationBhv.selectList(cb -> {
            cb.query().setParentId_Equal(parentId);
            cb.query().addOrderBy_ChildId_Asc();
        });
        return rels;
    }

    /**
     * Insert Element into database.
     * @param  dto    target element DTO
     * @param  isRoot whether argument DTO is root or not
     * @return        element entity after insertion
     */
    private MstElement insertElement(ElementDto dto, boolean isRoot) {
        MstElement element = ElementDxo.toElementEntity(dto);
        element.setId(null);
        element.setIsRoot(isRoot);
        mstElementBhv.insert(element);
        logger.info("    Element created: " + element);
        return element;
    }

    /**
     * Insert Relation into database.
     * @param  parentId parent element id
     * @param  childId  child element id
     * @return          relation entity after insertion.
     */
    private MstRelation insertRelation(int parentId, int childId) {
        MstRelation relation = new MstRelation();
        relation.setParentId(parentId);
        relation.setChildId(childId);
        mstRelationBhv.insert(relation);
        logger.info("    Relation created: " + relation);
        return relation;
    }

    /**
     * Get element from database by id.
     * @param  id element id
     * @return    ElementDto if entity exists, {@code null} otherwise
     */
    private ElementDto getElementDtoById(int id) {
        OptionalEntity<MstElement> op = mstElementBhv.selectEntity(cb -> {
            cb.query().setId_Equal(id);
        });
        if (op.isPresent()) return ElementDxo.toElementDto(op.get());
        return null;
    }

    /**
     * Get element from database by id.
     * @param  id element id
     * @return    element entity if it exists, otherwise {@code null}
     */
    private MstElement getElementEntityById(int id) {
        OptionalEntity<MstElement> op = mstElementBhv.selectEntity(cb -> {
            cb.query().setId_Equal(id);
        });
        if (op.isPresent()) return op.get();
        return null;
    }

    /**
     * Get relation from database by id.
     * @param  childId child element id
     * @return         relation entity if it exists, {@code null} otherwise
     */
    private MstRelation getUpwardRelation(int childId) {
        OptionalEntity<MstRelation> op = mstRelationBhv.selectEntity(cb -> {
            cb.query().setChildId_Equal(childId);
        });
        if (op.isPresent()) return op.get();
        return null;
    }

    /**
     * If parent has children, set it recursively by id.
     * @param parentDto parent ElementDto
     * @param childId   child element id
     */
    private void setChildren(ElementDto parentDto, int childId) {
        if (parentDto == null) return;
        ElementDto childDto = getElementDtoById(childId);
        if (childDto == null) return;
        // If child also has children, set it recursively
        setChildrenRecursively(childDto, childId);
        parentDto.children.add(childDto);
    }

    /**
     * Get relation with childId and call setChildren if they exist
     * @param childDto child ElementDto
     * @param childId  child element id
     */
    private void setChildrenRecursively(ElementDto childDto, int childId) {
        ListResultBean<MstRelation> rels = mstRelationBhv.selectList(cb -> {
            cb.query().setParentId_Equal(childId);
            cb.query().addOrderBy_ChildId_Asc();
        });
        rels.forEach(rel -> {
            setChildren(childDto, rel.getChildId());
        });
    }

    /**
     * Get root elements from database, and return their id.
     * @param  mode contents mode
     * @return      root elements id list
     */
    private List<Integer> getRootElementsId(int type) {
        ListResultBean<MstElement> elms = getRootElements(type);
        List<Integer> idList = new ArrayList<>();
        elms.forEach(elm -> {
            idList.add(elm.getId());
        });
        logger.info("    Root id list: " + idList);
        return idList;
    }

    /**
     * Get root elements with element type.
     * @param  type element type
     * @return      Element entity list
     */
    private ListResultBean<MstElement> getRootElements(int type) {
        return mstElementBhv.selectList(cb -> {
            cb.query().setIsRoot_Equal(true);
            cb.query().setType_Equal(type);
            cb.query().addOrderBy_Id_Asc();
        });
    }

    /**
     * Return the same ElementDto until argument DTO has different id.
     * @param  dto ElementDto
     * @return     parent if argument DTO has the same id as that of it,
     *                 argument DTO otherwise.
     */
    private ElementDto getParent(ElementDto dto) {
        if (parent != null && dto.id == parent.id.intValue()) return parent;
        parent = dto;
        return parent;
    }
}

所感

使用するテーブルはたったの二つだけですが、一方でアプリケーションロジックの実装がかなり大変でした。

もし同じ仕様を実装するなら

  • ドメイン駆動設計(注:完全な好み)
  • Compositeパターン
  • 閉包テーブル

等を使ってみるといいかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Debian 10でプリンタを使う

とても簡単だと思った。

EPSONのサイトでLinuxドライバが配布されている。
https://www.epson.jp/support/taiou/os/linux_se.htm

  1. 型番で対応しているか確認する
  2. ESC/P-R Driver (generic driver), Epson Printer Utility, All-in-one package のdebファイルをダウンロードする
  3. dpkg -i でインストールする。
# dpkg -i epson-*.deb
以前に未選択のパッケージ epson-inkjet-printer-escpr を選択しています。
(データベースを読み込んでいます ... 現在 236410 個のファイルとディレクトリがインストールされています。)
epson-inkjet-printer-escpr_1.7.7-1lsb3.2_amd64.deb を展開する準備をしています ...
epson-inkjet-printer-escpr (1.7.7-1lsb3.2) を展開しています...
以前に未選択のパッケージ epson-printer-utility を選択しています。
epson-printer-utility_1.1.1-1lsb3.2_amd64.deb を展開する準備をしています ...
epson-printer-utility (1.1.1-1lsb3.2) を展開しています...
dpkg: 依存関係の問題により epson-inkjet-printer-escpr の設定ができません:
 epson-inkjet-printer-escpr は以下に依存 (depends) します: lsb (>= 3.2) ...しかし:
  パッケージ lsb はまだインストールされていません。

dpkg: パッケージ epson-inkjet-printer-escpr の処理中にエラーが発生しました (--install):
 依存関係の問題 - 設定を見送ります
dpkg: 依存関係の問題により epson-printer-utility の設定ができません:
 epson-printer-utility は以下に依存 (depends) します: lsb (>= 3.2) ...しかし:
  パッケージ lsb はまだインストールされていません。

dpkg: パッケージ epson-printer-utility の処理中にエラーが発生しました (--install):
 依存関係の問題 - 設定を見送ります
libc-bin (2.29-10) のトリガを処理しています ...
処理中にエラーが発生しました:
 epson-inkjet-printer-escpr
 epson-printer-utility

だめでした。

成功した方法

# apt install printer-driver-escpr psutils cups

debパッケージが置いてあるサイトにアクセスすると分かるのだけれど、このパッケージはepson-inkjet-printer-escpr_.tar.gzから作成されている。

あとはプリンタの電源を入れておき、gnomeの設定画面で自動追加されたのを確認する。

参考にした文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FriendlyDesktop(Linux) can't boot

The SOM-RK3399 displayed FriendlyElec(that is the rogo before OS boot like Android) then nothing happen.
I guess the device couldn't boot. but I didn't find any data to solve the problem for friendlyDesktop OS.

So the way is Bold. just Flash FriendlyDesktop ROM again with AndroidTool_Release_v2.71 or more. that's the way I did.

After that the OS was boot without any problem.

Probably, it started when I changed all the permissions under /etc using chmod -R 777 /etc.
After that, a number of problems occurred, and the permissions under/ etc were changed many times by chmod. (I forgot 400 or 555 or 444 or other).

That is very ridiculous.

Probably, in linux, it is highly possible that the startup script is stored under /etc.
that is the reason the device couldn't boot I think.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ndroid でもとりあえず Ubuntu のデスクトップ環境を使いたい(Termux 版 - LXDEで日本語入力)

はじめに

Android でもとりあえず Ubuntu のデスクトップ環境を使いたい(Termux 版)
の続きです。
Ubuntu の LXDEデスクトップ環境で日本語入力を行うための設定を記載します。
fcitx-mozc はどうしても動作させることができなかった(オンになっているはずなのに、日本語が入力できない。。。)ので、fcitx-anthy を使用しています。

インストール

まずは日本語フォントおよび Anthy (日本語をキーボードから入力するためのツール)のインストールを行います。
dbus-x11 は入力ツールの不足分を補完します。
Ubuntu の LXDEデスクトップ環境を立ち上げてから、以下のコマンドを LXTerminal 等のシェルで実行して下さい。

apt install -y fonts-noto
apt install -y fcitx-anthy
apt install -y dbus-x11

設定

続いて入力ツールの設定ダイアログで設定を行います。
以下のコマンドでダイアログを開いて下さい。

fcitx-configtool

もしダイアログが立ち上がらなかったら以下のコマンドを実行してからもう一度、ダイアログを立ち上げて下さい。

fcitx-autostart

入力ツールのダイアログを表示したら以下の手順で Anthy を使えるように設定してください。

  1. Input Method タブを選択
  2. +ボタンを押す
  3. Only Show Current Language のチェックボックスからチェックを外す
  4. チェックボックスの下の入力欄に Anthy と入力する
  5. Anthy が上のボックスに出るので選択し、OKボタンを押す
  6. Anthy が上から2番目の位置になるよう ↑ や ↓ で移動する
  7. 続いて、Global Config タブを選択
  8. Trigger Input Method で日本語と英語を切り替えるボタンを設定する(任意です。ネットで見ると 右ALT や Shift+SPACE など好みで設定しているようです。)
  9. ダイアログの右上のxを押してダイアログを閉じる

続いて設定ファイルに環境変数とfcitxの起動コマンドを記載します。
以下のコマンドを実行して設定ファイルを編集します。

vim ~/.bashrc

以下を .bashrc ファイル内の適当な位置に記載します。
私は一番下に記載しました。

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx

fcitx > /dev/null 2>&1

最後に Termux を終了し起動し直します。
Android の通知領域に Termux の文字が2行出ているので上の方をタップします。
左下に Exit の文言が出ますので、Exit をタップします。
再び Termux + XSDL でLXDEデスクトップ環境を立ち上げるとAnthyで日本語入力できるようになります。

なお私の環境では Termux を再起動しないと Anthy で日本語入力出来ませんでした。
.bashrc を souce コマンドで読み込んでも駄目だったので、何か起動時に行わないといけないことがあるのかもしれません。

参考サイト

ChromebookのLinux(Crostini)の日本語入力をAnthyで構築

Chromebook C101PAでVSCodeを使う。(Crostini使用)

fcitxで「正しくfcitxに接続できません。」エラーが発生したときの対応

Chrombook C101PAにVisual Studio Codeをインストールしてみる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android でもとりあえず Ubuntu のデスクトップ環境を使いたい(Termux 版 - LXDEで日本語入力)

はじめに

Android でもとりあえず Ubuntu のデスクトップ環境を使いたい(Termux 版)
の続きです。
Ubuntu の LXDEデスクトップ環境で日本語入力を行うための設定を記載します。
fcitx-mozc はどうしても動作させることができなかった(オンになっているはずなのに、日本語が入力できない。。。)ので、fcitx-anthy を使用しています。

インストール

まずは日本語フォントおよび Anthy (日本語をキーボードから入力するためのツール)のインストールを行います。
dbus-x11 は入力ツールの不足分を補完します。
Ubuntu の LXDEデスクトップ環境を立ち上げてから、以下のコマンドを LXTerminal 等のシェルで実行して下さい。

apt install -y fonts-noto
apt install -y fcitx-anthy
apt install -y dbus-x11

設定

続いて入力ツールの設定ダイアログで設定を行います。
以下のコマンドでダイアログを開いて下さい。

fcitx-configtool

もしダイアログが立ち上がらなかったら以下のコマンドを実行してからもう一度、ダイアログを立ち上げて下さい。

fcitx-autostart

入力ツールのダイアログを表示したら以下の手順で Anthy を使えるように設定してください。

  1. Input Method タブを選択
  2. +ボタンを押す
  3. Only Show Current Language のチェックボックスからチェックを外す
  4. チェックボックスの下の入力欄に Anthy と入力する
  5. Anthy が上のボックスに出るので選択し、OKボタンを押す
  6. Anthy が上から2番目の位置になるよう ↑ や ↓ で移動する
  7. 続いて、Global Config タブを選択
  8. Trigger Input Method で日本語と英語を切り替えるボタンを設定する(任意です。ネットで見ると 右ALT や Shift+SPACE など好みで設定しているようです。)
  9. ダイアログの右上のxを押してダイアログを閉じる

続いて設定ファイルに環境変数とfcitxの起動コマンドを記載します。
以下のコマンドを実行して設定ファイルを編集します。

vim ~/.bashrc

以下を .bashrc ファイル内の適当な位置に記載します。
私は一番下に記載しました。

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx

fcitx > /dev/null 2>&1

最後に Termux と XSDLを終了し起動し直します。
Android の通知領域に Termux の文字が2行出ているので上の方をタップします。
左下に Exit の文言が出ますので、Exit をタップして Termux を終了します。
XSDL は Android の各ランチャーの手順に従って終了してください。
再び Termux + XSDL でLXDEデスクトップ環境を立ち上げるとAnthyで日本語入力できるようになります。

なお私の環境では Termux を再起動しないと Anthy で日本語入力出来ませんでした。
.bashrc を souce コマンドで読み込んでも駄目だったので、何か起動時に行わないといけないことがあるのかもしれません。

参考サイト

ChromebookのLinux(Crostini)の日本語入力をAnthyで構築

Chromebook C101PAでVSCodeを使う。(Crostini使用)

fcitxで「正しくfcitxに接続できません。」エラーが発生したときの対応

Chrombook C101PAにVisual Studio Codeをインストールしてみる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android でもとりあえず Ubuntu のデスクトップ環境を使いたい(Termux 版 - デスクトップ環境で日本語入力)

はじめに

Android でもとりあえず Ubuntu のデスクトップ環境を使いたい(Termux 版)
の続きです。
Ubuntu の LXDE、XFCEデスクトップ環境で日本語入力を行うための設定を記載します。
fcitx-mozc はどうしても動作させることができなかった(オンになっているはずなのに、日本語が入力できない。。。)ので、fcitx-anthy を使用しています。

インストール

まずは日本語フォントおよび Anthy (日本語をキーボードから入力するためのツール)のインストールを行います。
dbus-x11 は入力ツールの不足分を補完します。
Ubuntu の LXDE または XFCE デスクトップ環境を立ち上げてから、以下のコマンドを LXTerminal 等のシェルで実行して下さい。

apt install -y fonts-noto
apt install -y fcitx-anthy
apt install -y dbus-x11

設定

続いて入力ツールの設定ダイアログで設定を行います。
以下のコマンドでダイアログを開いて下さい。

fcitx-configtool

もしダイアログが立ち上がらなかったら以下のコマンドを実行してからもう一度、ダイアログを立ち上げて下さい。

fcitx-autostart

入力ツールのダイアログを表示したら以下の手順で Anthy を使えるように設定してください。

  1. Input Method タブを選択
  2. + ボタンを押す
  3. Only Show Current Language のチェックボックスからチェックを外す
  4. チェックボックスの下の入力欄に Anthy と入力する
  5. Anthy が上のボックスに出るので選択し、OKボタンを押す
  6. Anthy が上から2番目の位置になるよう、Anthy を選択してから + ボタンの右側にある ↑ ボタンや ↓ ボタンで移動する
  7. 続いて、Global Config タブを選択
  8. Trigger Input Method で日本語と英語を切り替えるボタンを設定する(※)
  9. ダイアログの右上のxを押してダイアログを閉じる

※任意です。ネットで見ると 右ALT や Shift+SPACE など好みで設定しているようです。
Android Studio を使っている人は、デフォルトで設定されている Ctrl+SPACE を別の設定に変えましょう。
Ctrl+SPACE は Android Studio のコード補完のショートカットになります。

続いて設定ファイルに環境変数とfcitxの起動コマンドを記載します。
以下のコマンドを実行して設定ファイルを編集します。

vim ~/.bashrc

以下を .bashrc ファイル内の適当な位置に記載します。
私は一番下に記載しました。

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx

fcitx > /dev/null 2>&1

最後に Termux と XSDLを終了し起動し直します。
Android の通知領域に Termux の文字が2行出ているので上の方をタップします。
左下に Exit の文言が出ますので、Exit をタップして Termux を終了します。
XSDL は Android の各ランチャーの手順に従って終了してください。
再び Termux + XSDL でデスクトップ環境を立ち上げるとAnthyで日本語入力できるようになります。

なお私の環境では Termux を再起動しないと Anthy で日本語入力出来ませんでした。
.bashrc を souce コマンドで読み込んでも駄目だったので、何か起動時に行わないといけないことがあるのかもしれません。

参考サイト

ChromebookのLinux(Crostini)の日本語入力をAnthyで構築

Chromebook C101PAでVSCodeを使う。(Crostini使用)

fcitxで「正しくfcitxに接続できません。」エラーが発生したときの対応

Chrombook C101PAにVisual Studio Codeをインストールしてみる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry PiのBad Knowledge

はじめに

Raspberry Pi(以下RPi)からLinuxを触り始めた人も多いと思います。
そのせいなのかわかりませんが、RPi関連の日本の記事はあまりよくない設定を推奨している場合が多々見受けられます。
(あまりよくない設定の記事を最初に書いた人からずっとよくない知識が受け継がれているのだと思うのですが・・・)
なので、きちんとした設定を書こうと思います。
※ちなみに、ここに記載されていることのほとんどは公式のドキュメント(Raspberry Pi Documentation
)を読めば書いてあるので、時間がある人はしっかり公式の物を読みましょう。

今回はRaspbian向けに書いています。

※特定の人を批判する目的で記載したわけではありません。

開発に最低限必要な物について

開発に使用できるパソコンを持っているという前提で書くと、よく書かれている

  • HDMIケーブル
  • モニタ
  • キーボード
  • マウス

は最悪なくてもいいです。RPiはヘッドレスインストールが出来る為、モニタ類がなくても設定は一通り出来るんですね。更にGUIを使用したい場合もVNCなどで繋げればいいです。ただ、完全に必要ないかと言われればそうではなく、リモート接続(OTG接続)が出来なくなった場合にモニタ類を直接繋いで何が原因か切り分けできたりするので持ってれば嬉しいレベルです。

※あまりいないとは思うのですが、Linux初心者の方でRPi上でGUIを使用して開発するぞ!って人や、CLIに恐怖を感じるレベルの人はこれらは持ってた方がいいかもしれないです。余計な躓きから開放されます。

セキュリティについて

よく書かれている

rootパスワードを設定しましょう!

これは嘘です。設定してはいけません。これはあえて設定されていません。設定されていない場合は使用不可となりますが、設定してしまうと使用可となってしまう為です。自らセキュリティ的に脆弱にしています。

ssh有効化について

よく書かれている

mkdir /boot/ssh

これは微妙です。マニュアルには以下のように記されています。

When the Pi boots, it looks for the ssh file. If it is found, SSH is enabled and the file is deleted. The content of the file does not matter
google翻訳:Piが起動すると、sshファイルを探します。見つかった場合、SSHは有効になり、ファイルは削除されます。

しっかりとファイルと記載されていますね。また、ファイルは削除されますとのことなのでディレクトリは削除されません。ゴミが残ります。後述するのですがこれだといろいろ不便&セキュリティ上問題があります。

また、これもよくある記載でこっちはマニュアルが悪いのですが1

絶対に拡張子のないsshというファイルにしましょう!(.txtがつかないように!)

みたいなのも微妙です。そんなに気を使わなくていいです。
これはsshを有効化しているユニットファイルが以下のようになっており、ssh.txtでも有効化するようになっている為です。

sshswitch.service
[Unit]
Description=Turn on SSH if /boot/ssh is present
ConditionPathExistsGlob=/boot/ssh{,.txt}
After=regenerate_ssh_host_keys.service

[Service]
Type=oneshot
ExecStart=/bin/sh -c "systemctl enable --now ssh && rm -f /boot/ssh ; rm -f /boot/ssh.txt"

[Install]
WantedBy=multi-user.target

これは起動時に実行される為、前述のディレクトリを作成してSSHを有効化する方法の場合、セキュリティ上の理由で後からSSHを無効にした際に再起動するとまたSSHが有効になる、という問題が起きてしまうんですね。

IPアドレスについて

これは別に悪いことではないんですが、もっと簡単な方法がありますよーという紹介です。

よくある記載で、

(SSHする際に)IPアドレスを確認して〜、固定IPアドレスを設定して〜

というのがあると思うのですが、新し目の開発環境であればBonjour(mDNS)を使用してSSHすることができます。
ちなみに以下のような感じで接続します。

root@0ec7cd4678a7:~# ssh pi@raspberrypi.local

おわりに

初学者に人気のコンテンツって、どうしてもアクセス数目当てで適当なことを書く人が多くなるイメージがあります。
何が正しいかをしっかり見極めた上で楽しいLinuxライフを送っていきましょう!


  1. SSH can be enabled by placing a file named ssh, without any extension, onto the boot partition of the SD card from another computer. 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud9からGitHubのレポジトリへアップする手順(エラー解決方法含む)

  • Git BashなどでGitを動かしたことがある。
  • GitHubのレポジトリは作成済。

という方で、

  • 「初めてAWS Cloud9上で開発を始めたため、作成したソースを、既にあるGitHubのレポジトリへアップしたい」

という方向けに作成しました。

私自身はgit bashでGit/GitHubを操作したことはありましたが、初めてCloud9でgitを扱う際、色々とエラーが出て困ったので、Cloud9用の記事が欲しかったなと思って作成しました。

なお、GitHubのレポジトリは「公開」にしている前提です。
(非公開だとまた手順が異なるよう)

※Git/GitHub初学者の方は以下の動画がおすすめです。
https://www.udemy.com/share/101vBkAEMYcFxTTHgE/

はじめに

まずはcloud9のターミナルを用意。
念のため、gitが入っているか確認します。(Cloud9だと当然入っていますが)

$ git --version
git version 2.14.5

ローカルレポジトリ作成

ローカルレポジトリを作成したい任意のディレクトリに移動し

$ git init

を実行すると、「.git」ディレクトリ(ローカルレポジトリ)が生成されます。

ステージングエリアにadd

まずは、ステージングエリアにadd

$ git add [file]

※git addのオプションについては以下がわかりやすかったので参照下さい。
https://note.nkmk.me/git-add-u-a-period/

ローカルレポジトリにcommit

そして、ステージングエリアにあるファイルをローカルレポジトリにcommit

$ git commit -m "[任意のメッセージ]"

リモートレポジトリの登録とgit push

commitできたら、cloud9上で作成したgitのローカルレポジトリには登録完了です。
次に、GitHubのレポジトリ(リモートレポジトリ)にpush(アップロード)する必要があります。
まずはリモートレポジトリの登録から

$ git remote add origin git@github.com:[自身のGitHubのレポジトリ].git

その後、

$ git push -u origin master

ここで下記のようなエラーが出る方がいると思います。

Permission denied (publickey). 
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists. 

上記のエラーは、それぞれの行ごとに、以下のような意味です。

パブリックキーで権限が拒否された。
リモートリポジトリが読み取れない。
アクセス権持っている?それともリポジトリ自体存在している?

エラーを解決していきましょう。

先ほど、リモートレポジトリの登録は完了したかと思います。
そのため、先ほどのエラーメッセージの「リモートレポジトリ自体存在している?」は問題ないということになり、
「アクセス権持っている?」が問題になります。

では、アクセス権を得ましょう。

GitHubへアクセスには、公開鍵が必要です。
開発環境で公開鍵を作成し、GitHubへ公開鍵を登録することでアクセスできるようになります。

公開鍵の作成

まずは、cloud9内のディレクトリに、公開鍵を作成します。

$ ssh-keygen -t rsa -C "[リモートレポジトリを登録した自分のメールアドレス(・・・@gmail.comなど)]"

(-Cより後のコメント部分はなくても実行可能ですが、GitHubに登録しているEmailアドレスを指定するのが一般的のようです)

「ssh-keygen」はSSH(Secure SHell)の公開鍵と秘密鍵を作成するコマンドです。
ちなみにオプションの意味は

  • 「-t rsa」・・・作成する鍵の暗号化形式を「rsa」で指定
  • 「-C "コメント"」・・・コメントを指定

もっと詳しく知りたい方は以下記事がよいと思います。
https://www.atmarkit.co.jp/ait/articles/1908/02/news015.html

実行すると、以下のメッセージが出てきます。Enter~から始まる行が3回あり、各行にて入力を求められますが、すべて何も入力せずEnterを押して問題ありません。

Generating public/private rsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again:

上記でEnterを3回押すと、以下のメッセージが表示され、公開鍵が作成されます。(randomart imageの箇所は適当に書き換えています)

Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:・・・・・・・・・・・・・・・・・・・・・・・・・・  ……………@gmail.com
The key's randomart image is:
+---[RSA 2048]----+
|....................       |
| ..........        |
|   ......= ......       |
|    *..... .....        |
|   ...... BS+       |
|    =...........o..      |
ho
host github
|   .................       |
|    ......o*=.....+       |
|    .E..........*......      |
+----[SHA256]-----+

その後、.sshディレクトリを確認すると、公開鍵が作成されているのがわかります。

$ ls ~/.ssh/
authorized_keys  id_rsa  id_rsa.pub  known_hosts

id_rsa.pubファイルの内容をコピー

下記コマンドでid_rsa.pubのファイル内容を表示し、中身をコピーします。
(lessコマンドで中身を見るのではなく、ファイルの中身をすべてコピーしてもOK)

$ less ~/.ssh/id_rsa.pub

ファイル内の以下のssh-rsaから始まる部分をコピーします。(メールアドレスまでコピーに含めても含めなくても特に変わりないのでどちらでも構いません)

ssh-rsa ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
・・・・・・・・・・・・・・・・・・・・・・・・・・・ [メールアドレス]

公開鍵をGitHubに登録

今コピーした部分を、GitHubに登録するのですが、まずGitHubにブラウザからアクセスし、右上の自分のプロフィール画像から「settings」をクリック

image2.png

そして、左側のメニューから「SSH and GPG keys」を選択し、「New SSH key」をクリックします。

image3.png

すると、登録画面が出てきます。
登録画面の「key」部分のテキストエリアに先ほどコピーした「ssh-rsa」から始まる文言を貼り付けます。
ちなみに、タイトルは何でも構いません。

image4.png

貼り付けができたら「Add SSH key」をクリック。

ここで、下記コマンドを打てば接続に成功できると書いている記事が多いですが、エラーが出て接続に失敗する場合もあります。

$ ssh -T git@github.com

configファイルの作成

接続に失敗する場合は、.sshのディレクトリ内に「config」というファイルを作成します。
vimで、ファイルの作成と中身の記述を行います。

$ vim ~/.ssh/config

configファイルの中身に、下記の文言を貼り付けます。
なお、IdentityFileの後のパスは、自身の「id_rsa」ファイルを格納しているパスに変えてください。

Host github github.com
  HostName github.com  IdentityFile ~/.ssh/id_rsa
  User git

新規作成ファイルの権限設定

作成できたら、権限設定をします。
新規でファイルを作成したので、適切な権限を設定し、適切に実行できるようにします。

作成した当初は、configファイルに何も権限がない状態。

しかし今回は、「所有者読み取り権限があり、その他のユーザには権限がない」という状態にする必要があります。

そのため、権限は600か400にします。
(書き込み権限はあってもなくてもよいため)

所有者以外には権限を与えてはいけません。
600にするならば、以下を実行します。

$ chmod 600 ~/.ssh/config

ssh実行

そして、下記を実行。

$ ssh -T git@github.com

実行し、下記のような文字列が出力されたらOK!

Hi [username]! You've successfully authenticated, but GitHub does not provide shell access.

これで、git pushが可能になります。

最後に、git pushを行う

git pushで、ローカルレポジトリのファイル類をリモートレポジトリにアップロードできます。

$ git push origin master

これで完了です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kali Linux のカスタマイズ ~初期設定~

はじめに

Kali Linuxを仮想環境で実行する環境を構築します。
備忘録です。

前提

VMware WorkstationやVirtualBoxなんかで仮想環境が出来上がっていて、インターネットへ接続できることを前提に書いています。そこまでの環境は皆さんで良しなにご用意下さい。あと、rootアカウントで実行しています。

構築環境

  • HostOS:Windows10 Enterprise (Version:1909)
  • VMware Workstation14
  • Kali Linux:VERSION="2020.1"

目次

1.アップデート
2.タイムゾーンの変更
3.スクリーンロックを無効化
4.日本語キーボードに対応させる
5.日本語入力できるようにする
6.隠しファイルの表示の有効化
7.Terminalの拡張
7.1.VMare Workstation(or VMware Player)のHotkey変更
8.独自コマンドをエイリアスに追加
9.コラム

1.アップデート

このあと色々パッケージ追加するのでエラーが出ないように始めにやっときます。

root@kali:~# apt update && apt upgrade -y && apt dist-upgrade -y && apt autoremove -y && apt autoclean -y'

2.タイムゾーンの変更

GUIで操作
1.[Settings]>[Details]を選択。
2.[Date&Time]>[Time Zone]>[JST(Tokyo,Japan)]へ変更する。

3.スクリーンロックを無効化

Kaliは、デフォで5分間操作しないとロックされる。
何かしらの処理をKali上で実行しつつ、日常業務はホストOS側で行いたいので次の手順で変更する。
節電したい人はそのままのほうがいいですよ。

GUIで操作
1.[Settings]>[Power]を選択。
2.[Power Saving]の[Blank Screen]を[Never]へ変更する。

4.日本語キーボードに対応させる

Kaliは、デフォで英語キーボードからの入力を想定している。
英語キーボードの人はそのままでいいが日本語キーボードの人は次の手順で変更する。

GUIで操作
1.[Settings]>[Region&Language]を選択。
2.[Input Sources]の[+]ボタンをクリック、[Japanese]を追加。
3.[Japanese]を選択した状態で、右下のキーボードアイコンをクリック、レイアウトを確認する。

5.日本語入力できるようにする

日本語パッケージをインストールして日本語(全角)を入力できるようにする。

1.Terminalを起動して次を実行する。

root@kali:~# apt install -y task-japanese task-japanese-desktop

2.再起動。
3.デスクトップ右下の[Leafpad]アイコンを選択、[EN]をクリック。
4.[Anthy(UTF8)]を選択します。
5.入力できればOK。私の環境では、[Ctrl]+[J]で英語⇔日本語を切り替えています。
※4.は[Setting]>[Region&Language]でも変更できるよ。
language.JPG

6.隠しファイルの表示の有効化

勉強のため[.]から始まるファイルも表示されるように変更する。
※ls -a,llコマンド使う人にはあんまり関係ないかも。

GUIで操作
1.[Files]>[view]>[Show Hidden Files]にチェックを入れる。
show_hiddenfile.JPG

7.Terminalの拡張

操作性向上のためTerminatorという拡張版Terminalをインストール。
好みがあるので必須ではありませんが。。

注意
Kali Linuxを仮想環境上に構築している方は、hotkey assignmentの[Ctrl]+[Alt]を変更しないとうまいこと利用できない。変更手順は7.1に記載。

1.Terminalを起動して次を実行する。

root@kali:~# apt install terminator -y

2.インストールが完了したら、デスクトップ左側のランチャーからアプリ一覧を起動。
3.[Terminator]を入力後、Terminatorアイコンを右クリック、[Add to Favorites]でデスクトップランチャーに追加されます。
terminator.JPG

便利なキーコマンド 操作
[Ctrl]+[Shift]+[o] 画面を水平に分割する
[Ctrl]+[Shift]+[e] 画面を垂直に分割する
[Ctrl]+[Shift]+[n] 分割した画面を順次移動する
[Alt]+[↑] 上の画面に移動する
[Alt]+[↓] 下の画面に移動する
[Alt]+[→] 右の画面に移動する
[Alt]+[←] 左の画面に移動する
[Ctrl]+[Shift]+[w] 現在のパネルを閉じる
[Ctrl]+[Shift]+[t] 新しいタブを開く
[Ctrl]+[PageUp] タブ間を移動する
[Ctrl]+[PageDown] タブ間を移動する

Ex. [Ctrl]+[Shift]+[o]の実行結果
terminator.02JPG.JPG

7.1.VMare Workstation(or VMware Player)のHotkey変更

VirtualBoxご利用の方は、別途調べてください。

1.ホストOSで[C:\Users\ユーザ名\AppData\Roaming\VMware\preferences.ini]を開く。
2.メモ帳などのエディターで起動して次を追記する。

Ex.Hotkeyを[Ctrl]+[Alt]+[Win]にする。”gui”と書かれた部分が、[Win]キー。

pref.hotkey.shift = "false"
pref.hotkey.control = "true"
pref.hotkey.alt = "false"
pref.hotkey.gui = "true"

8.独自コマンドをエイリアスに追加

以下のサイトで何となく理解した。
ユーザーの環境変数を設定するbashの設定ファイルと、カスタムプロンプトについて

どのファイルに追加するかは、色んな記事みても人によって意見が違う。
Kaliには、[.bash_aliases]が存在しないので、作るのも面倒だし[.bashrc]に直接書き込みました。おすすめのやり方、おすすめの独自コマンドあれば教えてくださいっ!

.bashrc ファイル

alias ll='ls -l'
alias ..='cd ..'
alias del='rm -i'
alias powerup='apt update && apt upgrade -y && apt dist-upgrade -y && apt autoremove -y && apt autoclean -y'

9.コラム

Linuxのディレクトリ構成

備忘録としてまとめたものを載せます。

ディレクトリ 概略
/ ルートディレクトリ。ファイルシステムの最上位に位置する。
/bin 基本となる実行ファイルやコマンド
/boot OSの起動に必要なファイル
/dev デバイスファイル
/etc システムの設定ファイル
/home ユーザーごとのホームディレクトリ
/lib 共有ライブラリ
/mnt ファイルシステムのマウントポイント
/media CDやDVDのマウントポイント
/opt アドオンのアプリやデータ
/proc カーネルやプロセスの情報
/root rootユーザーのホームディレクトリ
/sbin 基本となるシステム管理者用のバイナリファイル
/srv システムに固有のデータ
/tmp 一時的なスペース。再起動時にクリアされることもある。
/usr ユーザーに関連するプログラム。ライブラリ、文書、カーネルソース
/var メールやログといった可変データ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む