全デベロッパーが知っておくべきLinuxコマンド

1. 概要

誰もがサーバーにSSHで接続し、ターミナルでデバッグやアプリをデプロイするとき、正しいコマンドを探して右往左往した経験があるでしょう。本記事では、日常的に最もよく使われるLinuxコマンドをまとめます。ファイル管理、検索、テキスト処理、プロセス監視、ネットワーク確認、ログ表示などです。読み終えれば、Google検索に頼らずにすぐにデバッグできる「生存技能」コマンド集が手に入ります。

主にUbuntu/Debian上のbashを例としていますが、これらのコマンドはほぼ全てのディストリビューションで同じです。

2. 基本的なファイルとディレクトリ操作

mkdir -p ~/projects/order-service/src/main/java
cd ~/projects/order-service
touch application.properties
ls -la
  • mkdir -p は入れ子になったディレクトリツリーを作成し、既存のディレクトリでもエラーを報告しません。
  • touch は空のファイルを作成します(または既存のファイルのタイムスタンプを更新します)。
  • ls -la は全てのファイル(.envや.gitなどの隠しファイルも含む)をリストアップし、パーミッション、オーナー、サイズを表示します。
drwxr-xr-x  3 nonla nonla 4096 Oct  5 10:00 .
-rw-r--r--  1 nonla nonla    0 Oct  5 10:00 application.properties

いくつかのファイル移動・削除コマンドは注意が必要です:

cp -r src/ src-backup/     # ディレクトリを再帰的にコピー
mv OrderService.java OrderServiceImpl.java   # ファイル名変更または移動
rm -rf target/            # 再帰的に削除、確認なし

注意: rm -rf にはゴミ箱がなく、削除したら失われます。実行前に必ず pwd で現在のパスを確認してください。特に他の場所からコマンドをコピペした場合は要注意です。

3. findとgrepで検索

3.1. find — 条件に基づいてファイルを検索

find . -name "*.java" -newer pom.xml

このコマンドは、pom.xmlより後に変更された全ての.javaファイルを検索します。コミット前に何が変わったかを確認する際に便利です。

find . -type f -size +10M

10MBより大きいファイルを検索します。ログやビルドアーティファクトが容量を圧迫している場合に使用します。

3.2. grep — ファイル内のコンテンツを検索

grep -rn "PaymentService" --include="*.java" src/
  • -r サブディレクトリを再帰的に検索します。
  • -n 行番号を表示します。
  • --include 検索対象を.javaファイルのみに限定し、target/などを除外します。
src/main/java/com/nonla/OrderController.java:15:    private final PaymentService paymentService;

より複雑なフィルタリングが必要な場合、pipeを使ってgrepとfindを組み合わせます:

find . -name "*.log" | xargs grep -l "OutOfMemoryError"

xargs は find からのファイルリストを grep -l に渡します(patternを含むファイル名のみを表示し、内容は表示しません)。

4. awk、sed、cutでテキスト処理

これは「ログ解析」コマンドグループです。長いアウトプットからデータを抽出する際に極めて強力です。

cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -5
  • awk '{print $1}' 各ログ行の第1カラム(通常はIP)を取得します。
  • sort | uniq -c グループ化して出現回数を数えます。
  • sort -rn 数値で降順にソート、head -5 トップ5を取得します。
    152 192.168.1.10
     98 10.0.0.5
     47 172.16.0.3

スクリプトを書かずに最もリクエストを送信しているIPを素早く見つける方法です。

sed はファイル内のテキストを直接置換するために使用します:

sed -i 's/spring.profiles.active=dev/spring.profiles.active=prod/' application.properties

-i はファイルを直接編集します(in-place)。より安全にするには、sed -i.bak '...' を使用して自動的に.bakバックアップファイルを作成します。

cut はデリミタに基づいてカラムを分割します。単一カラムが必要な場合、awk よりも軽量です:

cat /etc/passwd | cut -d: -f1 | head -3

5. プロセスとシステムリソースの監視

ps aux | grep java

すべてのプロセスを表示し、java を含む行をフィルタリングします。Spring BootアプリケーションのPIDと実行状態を素早く確認する方法です。

nonla    12345  2.1  5.3 2345678 432100 ?      Sl   10:00   0:15 java -jar order-service.jar

2番目の列がPIDです。このPIDを使ってプロセスをkillするか詳細を確認できます:

kill -15 12345     # SIGTERM を送信、アプリにグレースフルシャットダウンを許可
kill -9 12345       # 強制終了、-15 が効かない場合のみ使用

注意: kill -9 はshutdown hook(コネクションプールのクローズ、ログのフラッシュなど)を実行させません。必ず -15 を先に試してください。

リアルタイムでリソースを監視する:

top -o %MEM

-o %MEM はプロセスをRAM使用量でソートします。メモリリークを疑う場合に便利です。より美しいインターフェースが必要な場合は htop をインストールしてください。

ディスク容量を確認する:

df -h
du -sh /var/log/*

df -h は各パーティションの容量を表示します(人間が読みやすい形式)。du -sh は /var/log 内の各サブディレクトリの容量を表示します。サーバーが「no space left on device」エラーを報告するときに非常に重要です。

6. ネットワークとポートの確認

ss -tulnp | grep 8080
  • ss は古い netstat の代替で、より高速です。
  • -t TCP、-u UDP、-l リスニング、-n 数値表示(DNS解決なし)、-p プロセス情報を含む。
tcp   LISTEN  0  128  0.0.0.0:8080  0.0.0.0:*  users:(("java",pid=12345,fd=45))

ポート8080がJavaプロセスのPID 12345に占有されていることが即座にわかります。Address already in use エラーに対処する際に非常に便利です。

curl でAPIを素早くテストする:

curl -s -X POST http://localhost:8080/api/orders \
  -H "Content-Type: application/json" \
  -d '{"customerId":1,"amount":99.5}'

-s サイレントモード(プログレスバー非表示)、-X POST HTTPメソッドを指定、-d JSONボディ。レスポンスヘッダも表示したい場合は -i を追加してください。

lsof コマンドは、プロセスが正確にどのファイル/ソケットを開いているかを知る必要があるときに使用します:

lsof -i :8080

7. ファイルアクセス権限

chmod +x deploy.sh
chown nonla:nonla application.properties
chmod 640 .env
  • chmod +x スクリプト実行権を付与します。
  • chown user:group オーナーを変更します。ファイルが別のユーザーに属する場合、通常 sudo が必要です。
  • chmod 640 はオーナーが読み書き可能(6)、グループは読み取りのみ(4)、その他は権限なし(0)を意味します。.env のような秘密ファイルの標準です。
-rw-r----- 1 nonla nonla 128 Oct  5 10:00 .env

注意: 本番環境で chmod 777 を使用しないでください。機械上の全てのユーザーが機密ファイルを読み取り・編集できるようにする最速の方法です。

8. 圧縮と解凍

tar -czvf order-service.tar.gz order-service/
tar -xzvf order-service.tar.gz -C /opt/apps/
  • -c アーカイブを作成、-x 解凍、-z gzipを使用、-v 詳細出力、-f ファイル名を指定します。
  • -C 解凍時に現在のディレクトリではなく目的のディレクトリを指定します。

デプロイ時、scp または rsync と組み合わせてサーバーにファイルを転送します:

scp order-service.tar.gz user@10.0.0.5:/opt/apps/
rsync -avz --progress target/*.jar user@10.0.0.5:/opt/apps/

rsync は変更部分のみを転送(デルタ転送)し、大きなファイルを複数回更新する場合に scp より大幅に高速です。

9. リアルタイムでログを表示

tail -f /var/log/order-service/app.log

-f(follow)はターミナルを開いたままにし、ファイルに新しい行が書き込まれるとすぐに表示します。本番環境のデバッグに必須のコマンドです。

tail時にパターンでログをフィルタリングする:

tail -f app.log | grep --line-buffered "ERROR"

--line-buffered は必須です。grep はデフォルトでブロック単位でバッファリングし、このフラグがないと tail -f とのパイプでアウトプットが遅延する可能性があります。

systemd の下でアプリが実行されている場合、ログファイルを手動で探す代わりに journalctl を使用してください:

journalctl -u order-service -f --since "10 minutes ago"

-u サービスユニットを指定、-f 追従、--since 時間を制限します。百万行の古いログを読む必要を避けられます。

10. JavaからLinuxコマンドを実行

JavaコードからシェルコマンドをJavaから直接呼び出す必要があることがよくあります。例えば、大きなファイルを書き込む前にディスク容量を確認する場合などです:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;

public class ShellRunner {

    public static String run(List<String> command) throws Exception {
        ProcessBuilder builder = new ProcessBuilder(command);
        builder.redirectErrorStream(true);
        Process process = builder.start();

        try (BufferedReader reader =
                new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String output = reader.lines().reduce("", (a, b) -> a + b + "\n");
            process.waitFor();
            return output;
        }
    }
}
  • ProcessBuilder はリスト引数を受け取ります(手でコマンド文字列を組み立てるのではなく、シェルインジェクションを回避します)。
  • redirectErrorStream(true) はstderrをstdoutにマージし、単一ストリームとして読むことができます。
  • process.waitFor() は子プロセスが終了するまで現在のスレッドをブロックします。

JUnit 5とAssertJでテストする:

import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;

class ShellRunnerTest {

    @Test
    void shouldReturnCurrentDirectoryListing() throws Exception {
        String output = ShellRunner.run(List.of("ls", "-la"));

        assertThat(output).contains("total");
    }
}

このテストは ls -la を実際にシステムで実行し、アウトプットが total 行を含むかをチェックします(ls -la の最初の行は常にブロック総数を表示します)。ProcessBuilder がシェルコマンドを実際に呼び出せることを確認します。

注意: Javaプロダクションコードからシェルコマンドを呼び出すのは両刃の剣です。OSに依存しやすく、テストしにくく、ユーザー入力から引数を取得する場合は注入のリスクがあります。内部ツールまたは運用スクリプトのみに使用し、コアのビジネスロジックには避けてください。

11. よくあるエラー

  • 環境変数が空の状態で rm -rf を実行する場合、例えば $DIR が未設定のときに rm -rf $DIR/* を実行すると、ルートディレクトリを誤削除します。スクリプトでは常に set -u を使用するか、実行前に変数をチェックしてください。
  • ルート権が必要なときに sudo を忘れると、曖昧な Permission denied エラーが発生します。ls -la で事前に確認してからアプリを疑ってください。
  • 習慣的に kill -9 を使用すると、Spring Bootアプリケーションがコネクションプールをクローズできずにデータベースにリークが生じます。
  • tail -f の後にパイプで grep をするときに --line-buffered を忘れると、ログが実行されていないと思いがちですが、実はバッファリングされています。
  • 権限エラーを急いで解決するために chmod 777 を実行すると、セキュリティホールが生じ、特に .env ファイルやSSHキーにとって危険です。

12. 結論

本記事のコマンド — find、grep、awk/sed、ps/kill、ss/curl、tar、tail -f、journalctl — は、DevOpsチームを待たずに自分でデバッグするための最小限のツールセットです。それらを習得することは全てのフラグを暗記することを意味しません。どのコマンドがどの問題を解決するかを知り、必要に応じて man で詳細を確認するだけです。ターミナルは依然として最速のデバッグツールです。Grafana、Kibana、APMツールが豊富にあっても変わりません。

linuxdevopsbash生産性java