プログラミングめもめも

プログラミングの学習メモです

detailsを使ったアコーディオン実装

「よくある質問」や「カテゴリ一覧」など、Webページでよく使われるアコーディオンアニメーションをdetailsとsummaryタグを使って実装する方法を紹介します。

これらのタグを使うと、JavaScriptでわざわざ実装しなくてもキーボード操作でのタブフォーカスができたり、スクリーンリーダーによってタブの開閉状態が読まれたり、アクセシビリティの最適化にも便利です。

以下の記事を参考にして、アコーディオンを実装してみました。

ics.media

完成見本

以下が完成デモです。

See the Pen accordion-details by hachicombu (@hachicombu) on CodePen.

HTML

detailssummaryタグのみで基本的な基本的な開閉アニメーションが実現します。

<details>
   <summary>質問内容</summary>
   <p>折りたたまれた回答です。</p>
</details>

See the Pen accordion-html by hachicombu (@hachicombu) on CodePen.

<summary>をクリックすると、折りたたまれた部分が開閉します。

また、<summary>要素をクリックすると、<details>要素にopen属性が付け外しされます。

これによりアコーディオンが開閉するので、<details open>〜</details>としておくとその要素は初期表示されます。

CSS

それぞれのdetails要素のHTML・CSS全文です。

<details class="qa__box js-details">
  <summary class="qa__summary js-summary">
    <span class="qa__summary-icon">Q</span>
    <span class="qa__summary-text">Lorem ipsum dolor sit amet.</span>
    <span class="qa__summary-button"></span>
  </summary>
  <div class="qa__answer js-content">
    <div class="qa__answer-inner">
      <span class="qa__answer-icon">A</span>
      <span class="qa__answer-text">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sequi, reiciendis.</span>
    </div>
  </div>
</details>
.qa__box {
  border-radius: 12px;
  border: 2px solid var(--color-brown);
  background: var(--color-white);
  overflow: hidden;

  &:nth-child(n + 2) {
    margin-top: 12px;
  }
}

.qa__summary {
  padding: 10px 14px;
  display: flex;
  flex-direction: row;
  gap: 12px;
  align-items: center;
  cursor: pointer;

  // safari用
  &::-webkit-details-marker {
    display: none;
  }
}

.qa__summary-icon,
.qa__answer-icon {
  color: var(--color-main);
  font-size: 24px;
  line-height: 1.25;
}

.qa__summary-text {
  font-size: 14px;
  font-weight: 700;
}

.qa__summary-button {
  background: var(--color-main);
  width: 26px;
  height: 26px;
  border-radius: 50%;
  position: relative;
  margin-left: auto;

  &::before,
  &::after {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: var(--color-white);
    width: 10px;
    height: 2px;
    border-radius: 20px;
    content: "";
  }

  &::before {
    transform: translate(-50%, -50%) rotate(90deg);
    transition: transform 0.3s;

    // QAが開いている時
    .qa__box.is-open & {
      transform: translate(-50%, -50%);
    }
  }
}

.qa__answer {
  overflow: hidden;
}

.qa__answer-inner {
  padding: 14px;
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--color-gray);
}

.qa__answer-text {
  font-size: 14px;
}

.qa__summary-buttonは開閉ボタンで、疑似要素で白い「+」「-」を実装しています。

::beforeが縦棒、::afterが横棒です。

JavaScriptアコーディオンが開いている時に<details>is-openクラスを追加して、transform:rotate();を無効化しています。

&::before {
  transform: translate(-50%, -50%) rotate(90deg);
  transition: transform 0.3s;

  // QAが開いている時
  .qa__box.is-open & {
    transform: translate(-50%, -50%);
  }
}

JavaScript

JavaScript全文です。Web Animations APIで実装しています。

document.addEventListener("DOMContentLoaded", () => {
  const details = document.querySelectorAll(".js-details");
  const RUNNING_VALUE = "running";

  details.forEach((detail) => {
    // 質問の部分
    const summary = detail.querySelector(".js-summary");
    // 回答部分
    const content = detail.querySelector(".js-content");

    summary.addEventListener("click", (e) => {
      // ブラウザのデフォルトの挙動を無効化
      e.preventDefault();

      // 連打防止
      if (detail.dataset.animStatus === RUNNING_VALUE) {
        return;
      }

      const isOpen = detail.classList.contains("is-open");

      // アコーディオンが開いている場合
      if (isOpen) {
        const closingAnim = content.animate(
          closingAnimKeyframes(content),
          animTiming
        );
        // detailsタグにis-openクラスを削除
        detail.classList.toggle("is-open");
        // アニメーション実行中のrunning属性を入れておく
        detail.dataset.animStatus = RUNNING_VALUE;

        // アニメーション終了時の動作を指定
        closingAnim.onfinish = () => {
          // open属性を削除
          detail.removeAttribute("open");
          // running属性を削除
          detail.dataset.animStatus = "";
        };
      } else {
        // アコーディオンが閉じている場合、open属性を追加
        detail.setAttribute("open", true);
        // is-openクラスを付与
        detail.classList.toggle("is-open");

        const openingAnim = content.animate(
          openingAnimKeyframes(content),
          animTiming
        );
        // アニメーション実行中のrunning属性を入れておく
        detail.dataset.animStatus = RUNNING_VALUE;

     // アニメーション終了時の動作を指定
        openingAnim.onfinish = () => {
          // running属性を削除
          detail.dataset.animStatus = "";
        };
      }
    });
  });
});

// 開閉アニメーションの再生時間と速度・タイミングを定義
const animTiming = {
  duration: 400,
  easing: "ease-in-out"
};

// アコーディオンを閉じるアニメーション
const closingAnimKeyframes = (content) => [
  {
    height: content.offsetHeight + "px",
    opacity: 1
  },
  {
    height: 0,
    opacity: 0
  }
];

// アコーディオンを開くアニメーション
const openingAnimKeyframes = (content) => [
  {
    height: 0,
    opacity: 0
  },
  {
    height: content.offsetHeight + "px",
    opacity: 1
  }
];

アニメーションを作成

アコーディオンの開閉アニメーションはWeb Animatins APIで登録します。 アコーディオンの高さと透明度を変化させるアニメーションです。

// 開閉アニメーションの再生時間と速度・タイミングを定義
const animTiming = {
  duration: 400,
  easing: "ease-in-out"
};

// アコーディオンを閉じるアニメーション
const closingAnimKeyframes = (content) => [
  {
    height: content.offsetHeight + "px",
    opacity: 1
  },
  {
    height: 0,
    opacity: 0
  }
];

// アコーディオンを開くアニメーション
const openingAnimKeyframes = (content) => [
  {
    height: 0,
    opacity: 0
  },
  {
    height: content.offsetHeight + "px",
    opacity: 1
  }
];

クリックイベント内で条件分岐

summary(summaryタグ)にクリックイベントを指定し、アコーディオンが開いている場合・閉じている場合で条件分岐して処理をしています。

summary.addEventListener("click", (e) => {
// ...

    if (isOpen) {
    // アコーディオンが開いている場合の処理
    }
    else {
    // アコーディオンが閉じている場合の処理
    }
}

それぞれで行う処理は主に3つです。

  • detailsタグのis-openクラスを付け外し(detail.classList.toggle()の部分)
  • detailsタグのopen属性を付与・削除(detail.setAttribute()またはdetail.removeAttribute())
  • Web Animations APIで作成したアニメーション関数を実行(openingAnim, openingAnimの部分)

アニメーション中の連打を防止

開閉アニメーション中に連打すると挙動が不安定になってしまうため、連打対策も追加します。

クリックイベント発火時、以下のようにdataset.animStatusrunningを追加することで、アニメーション中であることを表します。

detail.dataset.animStatus = RUNNING_VALUE;

アニメーション終了後にはdataset.animStatusを空にします。 onfinishはアニメーション終了時に実行されるイベントハンドラです。

openingAnim.onfinish = () => {
   // running属性を削除
   detail.dataset.animStatus = "";
};

クリックイベント発火時、まずrunning属性が入っているかを判定し、入っている場合はそのまま処理を終了(return)させます。

if (detail.dataset.animStatus === RUNNING_VALUE) {
  return;
}

まとめ

detailssummaryタグは、コードもシンプルでアクセシビリティにも効果的な便利なタグです。

今後アコーディオンを実装する時にも使っていきたいと思います。

Webサイトにダークモードを実装する方法【CSS / JavaScript】

CSSJavaScriptでダークモードを実装する方法です。

やることは次の通りです。

  • バイスの設定を反映させる
  • ユーザーがブラウザ上で切り替えできるようにする
  • ブラウザ上で切り替えた内容を記憶して、再読み込みした際にも設定を反映させる

バイスの設定を反映させる

まずは、各デバイスのシステム設定などで指定しているライトモード・ダークモードをそのままWebサイトに反映させます。

以下はサンプルです。ご自身のデバイス設定に合ったモードで表示されているはずです。

See the Pen darkmode-systemDefault by hachicombu (@hachicombu) on CodePen.

やり方は簡単で、CSSのカスタムプロパティでライトモード・ダークモードそれぞれの値を指定するだけです。

/* light mode */
:root {
  --background: #fff;
  --text-color: #333;
}

/* dark mode */
@media (prefers-color-scheme: dark) {
  :root {
    --background: #000;
    --text-color: #ddd;
  }
}

ライトモードは@media (prefers-color-scheme: light)のメディアクエリでもOKです。

これをHTML要素で使用すると、設定が反映されます。

html {
  padding: 2rem;
  transition: 0.5s;

  /*  色指定  */
  background-color: var(--background);
  color: var(--text-color);
}

ユーザーがブラウザ上で切り替えできるようにする

多くのサイトでは、ユーザーがボタンなどをクリックすることでライトモード・ダークモードを切り替えできるようになっています。

この機能を実現するためには、JavaScriptでクラスの付け外しなどを実装します。

やることは、次の2点です。

  • バイスで設定されているモードを判定し、初期表示時に反映させる
  • ボタンクリックでクラスを付け外し、モードを切り替える

サンプルではトグルボタンクリックでライトモード・ダークモードが切り替わります。

See the Pen dark-mode-without-storage by hachicombu (@hachicombu) on CodePen.

トグルボタンは以下のサイトから生成しました!便利!

pote-chil.com

OSで設定されているモードを判定し、初期表示時に反映させる

バイスの設定はwindow.matchMediaで取得します。

// デバイスの設定がダークモードかどうか
const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches;

developer.mozilla.org

CSSのメディアクエリと同じ書き方で、ダークモードかどうかが取得できます。

判定(boolean)はmatchesに格納されています。

上記で取得したisDarkModeから、初期表示時のモードを設定しておきます。

if (isDarkMode) {
  // HTML要素に.darkを追加
  rootEl.classList.add("dark");
  // トグルボタンをcheckedに
  btn.checked = true;
} else {
  // HTML要素から.darkを削除
  rootEl.classList.remove("dark");
  btn.checked = false;
}

バイス設定がダークモードの時はHTML要素に.darkを追加します。

トグルボタンのchecked属性はボタンの切り替えに使っています。

CSSのカスタムプロパティは次のように修正しました。

:root {
  --background: #fff;
  --text-color: #333;
  --button-bg: #ffac7533;
  --button-color: #ffac75;
}
:root.dark {
  --background: #333;
  --text-color: #ddd;
  --button-bg: #57525233;
  --button-color: #575252;
}

/* 以下は削除 */
/* @media (prefers-color-scheme: dark) {
  :root {
    --background: #000;
    --text-color: #ddd;
  }
} */

バイス設定がダークモードかどうかはJavaScriptで判定し、クラスを付けて管理するようにしたため、CSSのメディアクエリが必要なくなりました。

トグルボタンもモードにより色が変わるので、その設定も上記でしています。

ボタンクリックでクラスを付け外し、モードを切り替える

トグルボタンのクリックにより、.darkの付け外しをしています。

btn.addEventListener("click", () => {
  if (btn.checked) {
    rootEl.classList.add("dark");
  } else {
    rootEl.classList.remove("dark");
  }
});

ボタンのchecked属性がtrue(=ダークモード)の時はクラスを削除し、false(=ライトモード)の時は追加する処理です。

ブラウザ上で切り替えた内容を記憶して、再読み込みした際にも設定を反映させる

これまでの実装だと、手動で切り替えたモードがブラウザに記憶されておらず、再読み込みすると初期表示の状態に戻ってしまいます。

再読み込みやブラウザを閉じても直前の設定が反映されるように、ブラウザのローカルストレージを使って、トグルボタンクリック時に設定が保存されるようにします。

See the Pen switch-darkmode by hachicombu (@hachicombu) on CodePen.

まずはボタンのクリックイベントに、localStorage.setItem("theme", "dark");を追加します。

引数にkeyとvalueを指定すると、その値がローカルストレージに保存されます。

btn.addEventListener("click", () => {
  if (btn.checked) {
    rootEl.classList.add("dark");
    localStorage.setItem("theme", "dark");
  } else {
    rootEl.classList.remove("dark");
    localStorage.setItem("theme", "light");
  }
});

Chromeの場合は開発者ツール(F12)→ Application → Storage → Local storageから確認できます。

Lightモードを選んだ時

さらに、初期表示や再読み込み時にはローカルストレージの値を元に、ダークモードかライトモードかを指定します。

if (localStorage.getItem("theme") === "dark") {
  darkModeOn();
} else if (localStorage.getItem("theme") === "light") {
  darkModeOff();
}

これで、ブラウザを閉じて再表示しても、元の設定内容になっているはずです。

ローカルストレージのデータは、ブラウザ履歴からストレージデータを削除するか、JavaScript側で削除処理(localStorage.clear())を行わないと削除されません。

ブラウザを閉じたらデータが削除されるsessionStorageを使っても良いかな、と思いました。(再読み込みでは削除されません)

developer.mozilla.org

今回は以上です!

GitHub PagesでWebサイトを公開する方法

この記事では、GitHub Pagesを使ってWebサイトを公開する手順を紹介します。

GitHubアカウントさえあれば無料で公開できます。

サイト公開の手順は大きく分けて次の通りです。

今回の解説は、GitHubにアカウントを持っていることを前提としています。

すでにGihHubにソースをPushしている状態であれば、「4. 設定 > PagesでWebサイトの公開設定」のみをご覧ください。

1. GitHubリポジトリを作成

まずは公開するサイトのリポジトリGitHub上で作成します。

GitHubのマイページ→repositoryタブをクリックし、新規リポジトリを作成します。

リポジトリ作成画面でリポジトリ名を指定します。

Public(ソースコードが公開)、Private(非公開)はPublicを指定してください。

無料枠だとPublicでないとGitHub Pagesが使えないためです。

それぞれ設定し、「Create repository」をクリックすればリモートリポジトリが作成されます。

2. GitHub(リモートリポジトリ)と自分のPCのリポジトリを紐付け

上記で作成したリモートリポジトリに、自分のPCのリポジトリを紐付け、Pushします。

リモートリポジトリを新規作成した際に表示されるコマンドを、紐付けたいディレクトリで入力すればOKです。

# git初期セットアップ
git init
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:{リポジトリ名}
git push -u origin main

上記コマンドでリポートリポジトリと紐付け&Pushまでできます。

これができたら、ブランチを切ってサイトのコーディングを行います。

3. ソースコードGitHubにPush

ローカルでコーディングができたら、リモートリポジトリにPushします。

# 変更内容を全てステージング
git add .
# コミット
git commit -m 'コメント'
# リモートリポジトリにPush
git push origin main

mainブランチ以外で作業してPushする場合は、git push origin {ブランチ名}でリモートリポジトリにも同名のブランチが作成・Pushされます。

4. 設定 > PagesでWebサイトの公開設定

リモートリポジトリ(GitHub)にソースコードをPushできたら、最後にGitHub Pagesの設定です。

リポジトリページの「Setting」タブをクリックします。

左サイドバーの「Pages」をクリックしてください。

「Branch」設定エリアで公開したいブランチを選び、パスは「/(root)」のまま、「save」をクリックするとWebサイトが作成されます。

次のキャプチャのように、サイトURLが表示されればOKです。 「Visit site」をクリックしてWebサイトを見てみましょう。

URLが表示されるまで少し時間がかかります。しばらく経ったらページを再読み込みしてください。

最後に

GitHub Pagesはほんの数分で全世界に自分のWebサイトを公開できる便利な機能です。

ポートフォリオの公開などに便利だと思いました。 無料で利用できるので、ぜひ試してみてください。

セマンティックHTMLでマークアップを書きたい

セマンティックHTMLとは、要素の目的や役割に応じてHTMLのタグを使い分けることを言います。

ただ見た目を整えるだけなら全て<div>で作っても良いですが、見出しや文章の区切りなど、ドキュメントの構成を正しく伝えるためにはHTMLのセマンティック要素を使う必要があります。

例えば、最上位の見出しは<h1>、ナビゲーションは<nav>、文章のセクションは<section>で表すなどです。

セマンティック要素はおよそ100もあるようですが、その中でもずっと使い方が曖昧だったセクショニング・コンテンツと呼ばれる次の4つの要素についてまとめたいと思います。

  • section
  • article
  • aside
  • nav

そもそもなぜセマンティックHTMLで書く必要があるのか

セクショニング・コンテンツの使い方の説明の前に、そもそもセマンティックHTMLがなぜ重要かを、以下の3つの観点から紹介します。

  1. SEO対策
  2. Webアクセシビリティ
  3. コードの保守性

1. SEO対策

検索エンジンがWebサイトを探索する際、HTMLタグを参考にします。

セマンティックHTMLで構造的に正しいマークアップがされていると、クローラーがそのサイトを理解しやすくなり、結果的に検索順位の向上につながります。

2. Webアクセシビリティ

目の不自由なユーザーがWebサイトを操作する際、スクリーンリーダーと呼ばれる読み上げソフトを利用します。

適切なマークアップは、それらのユーザーが必要なコンテンツにアクセスするサポートをしてくれます。

3. コードの保守性

Webサイトはリリース後に何度も修正や更新が行われます。

その際、セマンティックHTMLでマークアップしていると、コードを見ただけで「この部分はどんな役割を表現しているのか」がすぐに理解でき、開発スピードが上がります。

developer.mozilla.org

セクショニング・コンテンツの役割と使い方

ここからは、4つのセクショニング・コンテンツについて詳細をまとめます。

以下の書籍を参考にしています。セクショニング・コンテンツ以外のHTMLタグへの理解も深まるのでおすすめです。

武器になるHTML - 柴田 宏仙

1. section

ページの章や節、項など自立したセクションを表します。

また<h1><h6>マークアップした階層を、より明確にするために使われます。

そのため、<section>には1つ以上の見出しタグが必要です。

<section>
    <h2>旅行先を選ぶ</h2>
    <p>目的地をお選びください。</p>

    <section>
      <h3>アジア</h3>
      <p>...</p>

      <section>
        <h4>東南アジア</h4>
        <p>...</p>
      </section>

      <section>
        <h4>南アジア</h4>
        <p>...</p>
      </section>
    </section>

    <section>
      <h3>ヨーロッパ</h3>
      ... 省略
    </section>
  </section>

2. article

マークアップした範囲を他から切り離しても、独立したコンテンツとして成り立つ場合に使います。

ブログ記事やニュース記事、ユーザーのコメントなど、個別に配信や再利用することを意図したコンテンツです。

<article>
    <h2>行ってよかった旅行先ベスト3</h2>
    <p><time datetime="2023-11-21">2023.11.21</time></p>

    <p>過去当社を利用されたことのあるお客様50名に聞いた、行ってよかった国・地域を紹介します。</p>
        ...省略

    <p>この記事を書いた人:xx支店店長</p>
</article>

<article>入れ子にする場合、内側の<article>は外側と関連するコンテンツになります(記事に対するコメントなど)。

<article>
    <h2>行ってよかった旅行先ベスト3</h2>
    <p><time datetime="2023-11-21">2023.11.21</time></p>

    <p>過去当社を利用されたことのあるお客様50名に聞いた、行ってよかった国・地域を紹介します。</p>
        ...省略

    <p>この記事を書いた人:xx支店店長</p>

    <section>
      <h3>コメント</h3>
      <article>
        <h4>タイはおすすめ</h4>
        <p>投稿者: Aya</p>
        <p><time datetime="2023-11-22 12:00">20分前</time></p>
        <p>この記事を読んでタイに行ってきました!</p>
      </article>
    </section>
  </article>

個人的に<section><article>の使い分けがややこしいと感じましたが、次のような基準で判断すると良いそうです。

  • section:サイトの話題を構成する一部
  • article:ブログやSNSで投稿した場合、それだけで1つのコンテンツとして成り立つ

Webサイトによくある「About(〇〇について)」「Contact(お問い合せ)」「Feature(特集)」など、ページを構成する1要素は<section>アーカイブの1記事などは<article>を使うと良さそうです。

3. aside

サイドバーなど、メイン要素から切り離せる補足情報や余談、広告などに使います。

4. nav

グローバルナビゲーション、パンくずリスト、目次などに利用します。

<nav>は複数指定可能ですが、主要なナビゲーション1つのみに<nav>を使うことが推奨されています。

なぜなら、<nav>はスクリーンリーダーでナビゲーションのランドマークと読み上げられ、ユーザーのページ移動の目印となります。

<nav>が複数あると区別がつきにくく、ユーザーの混乱を招く可能性があるからです。

そのため、フッターによくある利用規約やプライバシーポリシーなどは<nav>で囲む必要はありません。

以上、セマンティックHTMLのざっくりとしたまとめと、セクショニング・コンテンツの使い方の紹介でした。

私もまだまだ正しいマークアップができていないので(特にWebアクセシビリティの理解はほぼないです)、これからも学習を続けたいと思います!

Linux 基本コマンドまとめ

今回は、Linux の基本コマンド 18 個の使い方をまとめてみました。

Linux コマンドの使い方

cd

cd(change directory)は、現在いるディレクトリを変更できるコマンドです。移動先のディレクトリを指定します。

cd [ディレクトリ名]

/tmpディレクトリに移動

cd /tmp

何も指定しなければホームディレクトリに移動

cd

pwd
/Users/macbookpro # ホームディレクトリ

pwd

pwd(print working directory)は、自分が現在どの位置にいるのかを表示します。

pwd
/Users/macbookpro/Desktop

現在、/Users/macbookpro/Desktopディレクトリにいることがわかります。

ls

ls(list)は、ファイル名やディレクトリを指定して情報を取得できるコマンドです。

ディレクトリを指定した場合はそのディレクトリの中にあるファイル・ディレクトリ一覧を表示します。

ls [オプション] [ファイル名 or ディレクトリ]

カレントディレクトリの全てのファイル・ディレクトリを表示

ls
bye-world.js   hate.txt       hello          world-hello.ts
ha.py          hatena.md      hello-world.js

test1 ディレクトリの一覧を表示

ls test1
hello.txt

ファイル名を指定すると、その指定した名前のファイルのみを表示できます。

これを使うと、ワイルドカード(*や?)で特定の文字列や拡張子を含むファイルのみを表示することもできます。

ファイル名にhelloの文字列が含まれるファイルのみを表示

ls *hello*
hello          hello-world.js          world-hello.ts

拡張子が.jsのファイルのみを表示

ls *.js
bye-world.js   hello-world.js
オプション 説明
-a 隠しファイルも含めて全て表示
-l ファイルの詳細(ファイルタイプ、パーミッションなど)も表示
-r 逆順に並び替えて表示
-t 更新時間順に並び替えて表示

mkdir

mkdir(make directory)は、ディレクトリを作成するコマンドです。

mkdir ディレクトリ名

カレントディレクトリに test1 ディレクトリを作成

mkdir test1

test1/test2/test3など下位のディレクトリを一度に作成したい場合、-pオプションが必要です。(ディレクトリを作る際はその上位層ができていないと作成できない制約があるため)

mkdir -p test1/test2/test3

rmdir

rmdir(remove directory)は、ディレクトリを削除するコマンドです。

中身が空である時のみディレクトリを削除できます。

rm ディレクトリ名

test1 ディレクトリを削除

rmdir test1

-pをつけると、指定した階層までのディレクトリを一括削除できます。

rmdir test1/test2

中にファイルなど存在している場合にそのディレクトリごと削除したい場合、rm -rを使います。

rm -r test2

cat

cat は、ファイルの内容を表示するコマンドです。

cat ファイル名

hello.txt の中身を表示

cat hello.txt
hello world!!!
オプション 説明
-n 行番号を表示

less

less は、ファイルの内容を表示するコマンドです。

cat コマンドの場合、ファイルの中身が一度に全て表示されるため、ファイルの行数がたくさんあると表示が流れてしまいます(上にスクロールすると見れますが)。

less はファイルの中身の一部を表示して、残りはスペースを押して確認できます。

less hello.txt

【ページ操作】

操作 説明
スペース 次のページへ進む
b 前の一画面に戻る
f 次の一画面に進む
/単語 単語を検索(n キーで検索結果をジャンプ)
q 表示を終了

行数が多いファイルや、ファイルの上の方だけ確認したい場合は less の方が便利かもしれません。

tail

tail はファイルの終わり部分のみを表示するコマンドです。オプションで「末尾から n 行」を指定できますが、指定しない場合は 10 行を表示します。

tail [オプション] ファイル名

末尾から 5 行を表示

tail -n 5 text.txt
オプション 説明
-n 行 末尾から指定した行を表示
-c バイト 末尾から指定したバイト分を表示

touch

touch は空のファイルを新規作成するコマンドです。

touch new-hello.js

すでに存在しているファイル名を指定した場合、そのファイルの最終更新時間が変更されます。

ls -l hello.txt
-rw-r--r--  1 macbookpro  staff    15B Dec 21 13:04 hello.txt

touch touch hello.txt
ls -l hello.txt
-rw-r--r--  1 macbookpro  staff    15B Dec 21 16:31 hello.txt

rm

rm(remove)はファイルを削除するコマンドです。ディレクトリを削除したい場合はオプション-rが必要です。

rm [オプション] ファイル名

hello.txt を削除

rm hello.txt

複数ファイルを指定して削除できます。

rm hello.txt world-hello.ts

test1 ディレクトリを削除(ディレクトリ内の全てのファイル・ディレクトリが削除される)

rm -r test1/
オプション 説明
-i 実行前に確認する
-f 強制的に処理を実行
-r ディレクトリを削除

mv

mv(move)はファイル・ディレクトリを移動させるコマンドです。移動先を存在しない名前に指定した場合、ファイル名(ディレクトリ名)を変更できます。

mv [オプション] 移動元ファイル 移動先ファイル

hello.txt を test1 ディレクトリに移動

mv hello.txt test1

hello.txt のファイル名を hello2.txt に変更

mv hello.txt hello2.txt
オプション 説明
-i 実行前に確認する
-r 強制的に処理を実行

cp

cp(copy)はファイル・ディレクトリを複製するコマンドです。

コピー元のファイルとコピー先(新しいファイル名)を指定します。

cp [オプション] コピー元 コピー先

hello.txt を複製した new-hello.txt を作成

cp hello.txt new-hello.txt

コピー先のファイル名がすでに存在する場合、コピー先のファイルが上書きされるので注意が必要です。

hello.txt を bye ディレクトリに複製

cp hello.txt bye/

ls bye/
hello.txt # 複製されたファイルができる

ディレクトリを複製する場合はオプション-rをつけます。

ディレクトリの中にあるファイル・ディレクトリ全てが複製されます。

cp -r test1/ test2/
オプション 説明
-i 処理を実行する前に確認する
-r ディレクトリをコピーする
-p 元ファイルの情報を保持したままコピー

ln

ln(link)は、ファイルやディレクトリのリンクを作成できる機能で、リンク元ファイルとリンク先ファイルを指定します。

リンク先を削除しても元のファイルには影響ありません。

ln 元ファイル名 リンク先

リンクにはハードリンクとシンボリックリンクがあります。

  • ハードリンク:ファイルの実体を共有する。元のファイルが削除されてもアクセスできる。
  • シンボリックリンクリンク元の場所を示すもので、元のファイルが削除されるとリンクが機能しなくなる(ショートカットのようなもの)。

シンボリックリンクを作成する場合、オプションに-sをつけます。

ハードリンクを作成

ln test.txt test-link.txt

シンボリックリンクを作成

ln -s test.txt test-link.txt

find

find は、ファイルがどのディレクトリに存在するかを検索するコマンドです。

find 検索場所 [オプション] 検索対象

カレントディレクトリにある hello から始まる名前のファイルを探す

find ./ -name hello.*

ファイルの拡張子が.json のファイルを探す

find ./*.json -type f

※ファイルタイプ

今日アクセスした、拡張子が.json のファイルを探す

find ./*.json -atime 0

0 が今日、1 が昨日、2 が一昨日…というように、数値が「n 日前」になります。

また、「-1」などマイナスをつけると「n 日以内」、「+2」など+をつけると「n 日前以前(2 日前より前)になります。

昨日更新した拡張子が.json のファイルを探す

find ./*.json -mtime 1 # -mtimeは更新日で探すオプション

拡張子が.json で中身が空のファイルを探す

find ./*.json -empty
オプション 説明
-name ファイル名(ディレクトリ名)を指定して検索。大文字と小文字を区別する
-iname 大文字・小文字を区別しない
-type ファイルタイプを指定
-atime ファイルにアクセスした日
-mtime ファイルの更新日
-empty 空のファイル・ディレクト

chmod

chmod(change mode)は、ファイルの権限を変更できるコマンドです。

ファイル所有者、ファイル所有グループ、その他ユーザーごとに読み・書き・実行権限を指定できます。

実行権限の指定方法は、

  1. モードの変更をカンマ区切りで指定
  2. 3 桁で各ユーザーの権限を指定

の 2 種類あります。

1. モードの変更をカンマ区切りで指定

chmod 変更対象 変更方法 変更内容 対象ファイル

変更対象、変更方法、変更内容はそれぞれ以下の中から指定します。

【変更対象】

変更対象 意味
u 所有ユーザー
g 所有グループ
o その他のユーザー
a 全て

【変更方法】

変更方法 意味
= その内容に設定
+ 追加
- 取り消し

【変更内容】

変更内容 意味
r 読み取り
w 書き込み
x 実行

例えば、「所有ユーザーに実行権限を付与」は次のようになります。

chmod u+x test.txt

複数指定ももちろん可能です。カンマ区切りで指定します。

# 複数対象に権限を付与(取り消し)
chmod u+rw-x,go+r-wx test.txt

2. 3 桁で各ユーザーの権限を指定

権限を数値 3 桁で指定する場合、所有ユーザー、所有グループ、その他ユーザーの順で次の表の合計値を指定します。

パーミッション 数値
r 4
w 2
x 1
# rwxr-xr-xに変更
chmod 755 test.txt

# rw-r—r—に変更
chmod 644 test.txt

# r————に変更
chmod 400 test.txt

chown

chown (change owner)は、ファイルの所有者を変するコマンドです。

ユーザーとグループを変更するには、root ユーザーである必要があります。

chown [オプション] ユーザーorグループ 変更対象

test.txt もユーザー所有権を root に変更

chown root test.txt

test.txt のユーザー・グループ所有権を root に変更

# 「ユーザー:グループ」で変更できる
chown root:root test.txt

ディレクトリを変更対象とする場合は、オプション-Rをつけます。

chown -R root test1/

ps

ps は、現在実行されているプロセス一覧を表示するコマンドです。プロセス ID、端末、CPU 時間、コマンド名などが表示されます。

ps [オプション]

プロセスとは、OS 上で実行中のプログラムのことです。プログラムは CPU やメモリのコンピューターリソースを消費して動いています。安定動作時(アイドリング状態)のプロセス数がどれくらいなのかを把握するのは管理上重要です。

実行中のプロセスをリスト形式で表示

ps aux
オプション 意味
-A, -e 全てのプロセスを選択
a 端末を持つ全てのプロセスを表示
x 端末を持たない全てのプロセスを表示
r 実行中のプロセスのみを表示
-p プロセス ID を指定して表示
u 見やすいフォーマットで表示
-l 長いフォーマットで表示
e コマンド名の後に環境を表示

kill

kill は、実行中のプロセスを終了させるコマンドです。異常な動作をしていたり、PC に負荷をかけているプロセスを止める際に使用します。

kill [オプション] プロセスID

最後に

今まで何度か Linux コマンドを使っていましたが、改めて勉強すると知らない使い方や便利なオプションをたくさん知れて、非常に勉強になりました。

Linux は一度身につければずっと使える知識なので、今後も便利な使い方などを積極的に学んでいきたいです。

ご覧いただきありがとうございました!

環境変数PATHの確認・追加・削除

この記事では、zshmacOSでパスを確認・追加・削除する方法を紹介します。

当方の環境は次の通りです。

  • OS:macOS Monterey 12.7.6
  • Shell:zsh

※Shellの種類はターミナルで以下を入力すると確認できます。

$ echo $SHELL
# 結果
/bin/zsh

「パスを通す」とは

「パスを通す」とは、コマンドの実行ファイルが存在するディレクトリのフルパスを環境変数PATHに登録(エクスポート)することを言います。

パスを通していると、コマンドを叩くことで処理が実行されるようになります。

例えば、ファイルを移動させるmvコマンドは/bin/mvにあります。

$ which mv
/bin/mv

このmvコマンドをフルパスで入力しなくても実行できるのは、mvが存在する/binのパスが通っている(環境変数PATHに登録されている)からです。

環境変数PATHは、echo $PATHで確認できます。

$ echo $PATH
/Users/{user}/.nodebrew/current/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

/binが登録されているのがわかります。そのため、mvコマンドは/bin/mvと打たなくても実行できるのです。

パスの通し方

パスを通すためには、zshrc(zshの設定ファイル)にパスを追加します。

vim(vi)コマンドでzshrcを編集できます。

$ vim ~/.zshrc

export PATH=追加したいコマンド検索パス:$PATHで追加できます。

例えば、/usr/bin/optを追加したい場合、次のようになります。

$ export PATH=/usr/bin/opt:$PATH

上書き保存をしたら、変更を反映します。

$ source ~/.zshrc

これで再度echo $PATHでパスが通っているか確認してください。

変更されていない場合、ターミナルを再起動すると反映されます。

不要なパスを削除

不要なパスを削除するのは、zshrcを編集すれば良いだけです。

# .zshrcを開く
$ vim ~/.zshrc

exportしている箇所をコメントアウトまたは削除してください。

# export PATH=$HOME/.nodebrew/current/bin:$PATH

最後に、変更を反映します。

$ source ~/.zshrc

これでパスの削除が完了です。

Vim の使い方とメリット、よく使うコマンドを紹介します。

Vim とは、ターミナル上で操作できるテキストエディタです。

コマンド操作でファイルの編集や保存ができるので、マウスを使わず、高速に作業できる点が魅力です。

今回は、Vim を使うメリットや使い方、よく使うコマンドをまとめてみました。

※当方の環境は Mac なので、使い方の紹介やコマンドは Mac を想定しています。

なぜ Vim を習得すべきなのか

Vim の使い方の前に、私が考える Vim を習得することのメリットを紹介します。

1. キーボードのみで操作するので時短・作業効率化につながる

Vim はターミナル上でコマンドを入力して移動や編集をします。マウスは使えません。

マウスやトラックパッドを使うと、キーボードからマウスに手を動かす手間が発生します。ほんのちょっとした時間ではありますが、チリも積もれば結構な時間になってしまいます。

その時間を短縮できたら、作業の効率化につながり、生産性もアップするはずです。

2. ちょっとした修正がすぐにできる

git にコミットする前やリリース対応前など、「ちょっとコードを修正したい」という時があります。

その度にいちいちエディタを開くより、ターミナル上でサクッと修正した方が早いです。

また、リリース対応などサーバールームで作業する際、VSCode などのエディタが使えない環境もあります。その際に Vim が使えないと、修正ができず困ってしまう可能性もあります。

Vim の使い方

ここから、Vim の具体的な使い方を紹介します。

1. Vim の起動

ターミナルでvimと入力するだけで起動します。

特定のファイルを開く場合は、ファイル名を指定すれば OK です。

# Vimを起動
$ vim
# 特定のファイル(sample.txt)を開きたい場合
$ vim sample.txt

2. モード切り替え

Vim には次の 4 つのモードがあり、それぞれ切り替えて使用します。

モード できること
ノーマルモード カーソル移動、コピー・ペースト、元に戻すなど
インサートモード 文字入力など編集作業
コマンドモード Vim の終了・保存、検索など
ビジュアルモード 範囲指定など

起動時はノーマルモードです。

それぞれのモードで作業中でも、escを押せばノーマルモードに戻ります。

Vim コマンド集

それぞれのモードでよく使うコマンドを紹介します。

ノーマルモード

カーソル移動

コマンド 説明
k 上に移動
j 下に移動
l 右に移動
h 左に移動
0(または^) 文頭に移動
$ 文末に移動
gg ファイル先頭に移動
G ファイル最後の行に移動

挿入

以下のコマンドでノーマルモード → インサートモードになります。

コマンド 説明
i インサートモード
a 次の文字からインサートモード
o 1 行下に挿入
O 現在行に挿入

削除

コマンド 説明
x 1 文字削除
dd 1 行削除
dx 単語を削除
u 1 つ前の状態に戻す

コピー・ペースト

コマンド 説明
yy 1 行コピー
p 1 行下にペースト
P 現在の行にペースト

コマンドモード

終了・保存

コマンド 説明
:q 編集終了
:q! 保存しないで終了
:w 上書き保存
:wq 保存して終了

検索・置換

コマンド 説明
/ 検索
n 次の検索結果に移動
r 置換(1 文字)
R 置換(2 文字以上)
:%s/{置換前}/{置換後}/g 一括置換

その他

コマンド 説明
:set number 行数を表示

ビジュアルモード

ビジュアルモードに切り替えるには、ノーマルモードvを押します。

k, j, l, hでカーソル移動をすると範囲選択できるので、そこからy → p(コピー・ペースト)、d(削除)などをすると良いです。

最後に

コマンドはとにかく使いまくって手に馴染ませるのが一番早いと思います。

使い慣れてくると、VSCodeなどのエディタを起動する少しの時間も惜しくなってきます。

普段のコーディングはエディタ、簡単な修正や追加などは Vim、といった使い方が良いかもしれません。