【2026年10月15日時点の情報です】
このブログは、自宅のAlmaLinuxサーバーでWordPressを動かしています。サイトの整理では、データベースのコマンドのほかに、ページの転送がうまく動いているかを確かめたり、大きな画像を探したり、フォルダを片付けたりするコマンドも、AI(Claude)に教わりながら何十回も実行してきました。
ただ、こちらもデータベースのコマンドと同じく、意味が分からないままコピーして貼り付けていました。そこで、実際に使ったコマンドを、場面ごとに「何のためか」「それぞれの部分の意味」から整理しました。
どのコマンドも、サーバーにSSHでつないだ画面(ターミナル)で、1行ずつ、またはまとめて貼り付けて実行しています。
コマンドを読むための基本の部品
長いコマンドも、分けてみると、同じ部品の組み合わせでした。先に、よく出てくる部品をまとめておきます。
| 部品 | 意味 | 例 |
|---|---|---|
| | (パイプ) | 左のコマンドの結果を、右のコマンドに渡す | curl … | grep … |
| > | 結果を、右のファイルに書き込む(上書き) | … > ~/work-list.txt |
| >> | 結果を、右のファイルの最後に書き足す | … >> ~/work-list.txt |
| 2>/dev/null | エラーの表示を捨てる(/dev/null は、入れたものが消える場所) | du -sh ~/.[!.]* 2>/dev/null |
| && | 左のコマンドがうまくいったときだけ、右のコマンドを実行する | cd ~/work && ls |
| 名前=値 | 変数(一時的な入れ物)に値を入れる。= の前後に空白を入れない | S=embedded-to-web-extra-git |
| $名前 | 変数の中身を使う | https://softdev-learn.cc/$S/ |
| $(コマンド) | コマンドの結果を、その場所に入れる | n=$(curl …) |
| \ (行の最後) | 「次の行に続く」という印。長いコマンドを読みやすく折り返す | for s in A \ B |
もう1つ大事なのが、sudo です。sudo を付けると、管理者の権限で実行されます。データベースや、Webサーバーのフォルダ(/var/www/html)の中は、管理者でないと読み書きできないので、そこを触るコマンドには sudo を付けていました。
sudo -v- sudo -v:
先に管理者のパスワードを聞いておく命令。長いコマンドの途中で sudo のパスワードを聞かれると、結果の表示が途中で止まって見えることがあるので、最初に実行しておく
場面1:ページが転送されているか、なくなっているかを確かめる
記事を消したり、URLを変えたりしたときは、古いURLがちゃんと新しいURLへ転送(301)されているかを確かめていました。
curl -sI https://softdev-learn.cc/ts-express-api-step7-git/ | grep -iE "^(HTTP|location)"結果の例:
HTTP/2 301
location: /embedded-to-web-extra-git/- curl:
URLを開いて、返ってきた内容を表示するプログラム(ブラウザの代わり) - -s:
途中経過(ダウンロードの進み具合など)を表示しない - -I:
ページの本文ではなく、最初に返ってくる「見出し」(ヘッダー)だけを取ってくる。転送かどうかは、この見出しを見れば分かる grep -iE "^(HTTP|location)":
見出しの中から、HTTP か location で始まる行だけを残す。-i は大文字・小文字を区別しない、-E は ( | ) の書き方を使う、^ は「行の始まり」の意味
1行目の数字(ステータスコード)で、ページの状態が分かります。
| 数字 | 意味 |
|---|---|
| 200 | ふつうに表示できる |
| 301 | 別のURLへ転送している。転送先は location の行に出る |
| 404 | ページが見つからない |
| 410 | ページはもうない(わざと消したことを伝える) |
実際に、旧記事が301ではなく410のままになっていたことも、このコマンドで気づけました。
数字だけを出す
数字だけが欲しいときは、次の形にしました。
curl -s -o /dev/null -w "%{http_code}\n" https://softdev-learn.cc/embedded-to-web-extra-git/- -o /dev/null:
ページの本文を捨てる(画面に出さない) -w "%{http_code}\n":
終わったあとに、ステータスコードだけを書き出す。\nは改行
場面2:たくさんのURLを、順番にまとめて確かめる
新しい連載を公開したときに、旧シリーズの6本の記事が、それぞれ新しい記事へ転送されているかを、1回で確かめたのが次のコマンドです。
for s in ts-express-api-step7-git:embedded-to-web-extra-git \
ts-express-api-step4-express-setup:embedded-to-web-07-deploy \
ts-express-api-step2-tsconfig:embedded-to-web-05-typescript-vs-c \
react-typescript-blood-test-app-2:embedded-to-web-04-vite \
deploy-react-node-almalinux-1:embedded-to-web-02-step0-hello \
deploy-react-node-almalinux-2:embedded-to-web-02-step0-hello; do
old=${s%%:*}; new=${s##*:}
o=$(curl -s -o /dev/null -w "%{http_code}" https://softdev-learn.cc/$old/)
n=$(curl -s -o /dev/null -w "%{http_code}" https://softdev-learn.cc/$new/)
echo "旧 $o /$old/ → 新 $n /$new/"
done結果の例:
旧 200 /ts-express-api-step7-git/ → 新 200 /embedded-to-web-extra-git/
旧 301 /ts-express-api-step4-express-setup/ → 新 200 /embedded-to-web-07-deploy/1行ずつ見ていきます。
for s in A B C; do … done:
A、B、C を1つずつ順に s に入れて、do から done までをくり返す。ここでは、「旧記事のスラッグ:新記事のスラッグ」の組が6つ並んでいる- 行の最後の
\:
「まだ続く」という印。6つの組を1行に書くと読みにくいので、折り返している old=${s%%:*}:
s の中身から、「:(コロン)とそのあと全部」を消したもの。つまり、コロンより前の旧記事のスラッグになるnew=${s##*:}:
s の中身から、「最初からコロンまで全部」を消したもの。つまり、コロンよりあとの新記事のスラッグになるo=$(curl …):
場面1の「数字だけを出す」curl の結果(ステータスコード)を、変数 o に入れる。n も同じで、新記事のほうecho "…":
文字を表示する。” ” の中の$oや$oldは、変数の中身に置き換わる;(セミコロン):
1行に2つのコマンドを書くときの区切り
結果を見ると、1行目の「旧 200」は、旧記事がまだ表示されていて転送されていない、という意味です。このときは、この1本だけ転送のルールを追加しました。
公開後のチェックをまとめて行う
記事を公開したあとの確認も、同じ部品の組み合わせで、まとめて行いました。
S=embedded-to-web-extra-git; U=https://softdev-learn.cc/$S/
H=$(curl -s "$U")
echo "== タイトル"; echo "$H" | grep -oE "<title>[^<]*</title>"
echo "== 検索に出す設定"; echo "$H" | grep -oiE "<meta name=.robots.[^>]*>"
echo "== canonical"; echo "$H" | grep -oiE "<link rel=.canonical.[^>]*>"H=$(curl -s "$U"):
ページの中身(HTML)を1回だけ取ってきて、変数 H に入れておく。調べるたびに取りに行かなくて済む"$U"、"$H":
変数を ” ” で囲むと、中に空白や改行があっても、1つのまとまりとして扱われる。HTMLは改行だらけなので、囲まないと正しく渡らないgrep -oE "<title>[^<]*</title>":
HTMLの中から、タイトルの部分だけを取り出す。[^<]*は「< 以外の文字がいくつか」で、タイトルの文字の部分にあたる- robots の行:
noindex(検索に出さない)が入っていないかを見る - canonical の行:
検索エンジンに伝えている「正しいURL」が、記事自身のURLになっているかを見る
場面3:データベースの結果を、1行ずつ処理する
非公開や下書きにした記事のURLが、404(ページが見つからない)になっていないかを調べたときのコマンドです。データベースから記事の一覧を取り出して、1本ずつ curl で確かめています。
sudo mysql wordpress -N -e "SELECT post_name, post_status FROM wp_posts WHERE post_type = 'post' AND post_status IN ('private','draft') AND post_name <> '' ORDER BY post_name;" \
| while IFS=$'\t' read slug st; do
code=$(curl -s -o /dev/null -w "%{http_code}" "https://softdev-learn.cc/$slug/")
[ "$code" = "404" ] && echo "$code $st /$slug/"
donesudo mysql … -N -e "SELECT …":
データベースから、非公開(private)と下書き(draft)の記事のスラッグと状態を取り出す。-N は、一番上の列の名前を出さない(1行目から記事が並ぶ)| while … read slug st; do … done:
前のコマンドの結果を1行ずつ読んで、1つ目の値を slug、2つ目を st に入れて、do から done までをくり返すIFS=$'\t':
1行を「どこで区切るか」をタブにする。mysql の結果は、列の間がタブで区切られているため[ "$code" = "404" ] && echo …:
[ ] は条件の判定。ステータスコードが404のときだけ、&& の右の echo が実行される。404でない記事は何も表示されない
結果に出てきた記事だけを見て、転送が必要かどうかを判断しました。
場面4:数えて、多い順に並べる
代替テキストが空の画像が、どの記事に何枚あるかを数えたときのコマンドです。
sudo mysql wordpress -N -e "SELECT post_name, post_content FROM wp_posts WHERE post_type = 'post' AND post_status = 'publish';" \
| awk -F'\t' '{n=gsub(/<img[^>]*alt=""/, "&", $2); if (n>0) print n "\t" $1}' | sort -rn > ~/work/alt-empty.tsv
wc -l ~/work/alt-empty.tsv
head -20 ~/work/alt-empty.tsv- awk:
1行ずつ読んで、列ごとに計算や表示をするプログラム -F'\t':
列の区切りをタブにする。$1が1列目(スラッグ)、$2が2列目(本文)gsub(/パターン/, "&", $2):
本文の中で、パターンに当てはまる部分を置き換えて、置き換えた回数を返す。”&” は「見つかった文字そのもの」なので、中身は変わらず、回数(=代替テキストが空の画像の数)だけが分かるif (n>0) print n "\t" $1:
1枚以上ある記事だけ、「枚数、タブ、スラッグ」を表示するsort -rn:
数字として(-n)、大きい順(-r)に並べる> ~/work/alt-empty.tsv:
結果をファイルに保存するwc -l:
ファイルの行の数(=代替テキストが空の画像がある記事の数)を数えるhead -20:
最初の20行(多い記事の上位20)だけを見る
このときは70本の記事が見つかり、そのあと、見出しから代替テキストを入れるスクリプトで、まとめて埋めました。
場面5:大きいファイルを探す
ページの表示を軽くするために、1MBを超える大きな画像を探したときのコマンドです。
cd /var/www/html/wp-content/uploads
find . -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" \) ! -regex '.*-[0-9]+x[0-9]+\..*' -size +1M -printf "%s\t%p\n" \
| sort -rn | awk -F'\t' '{printf "%.1fMB\t%s\n", $1/1048576, $2}' | head -30- cd フォルダ:
そのフォルダに移動する。WordPressの画像は、wp-content/uploads に入っている find .:
今いるフォルダ(.)の中を、下のフォルダまで全部探す-type f:
ファイルだけ(フォルダは除く)\( -name "*.jpg" -o … \):
名前が .jpg・.jpeg・.png で終わるもの。-o は「または」、かっこは条件をまとめる印で、シェルに別の意味で読まれないように \ を付けている! -regex '.*-[0-9]+x[0-9]+\..*':
! は「ではない」。WordPressが自動で作る縮小版(名前が -1024×576.jpg のように終わるもの)を除いて、元の画像だけにする-size +1M:
1MBより大きいもの-printf "%s\t%p\n":
見つかったファイルを、「大きさ(バイト)、タブ、場所」の形で表示するsort -rn:
大きい順に並べるawk … $1/1048576:
バイトを1048576(1024×1024)で割って、MBで表示する。%.1f は小数1けた
場面6:フォルダの容量を調べて、片付ける
作業用のフォルダが散らかってきたときに、何がどれだけ場所を取っているかを調べました。
cd ~/work && ls -lhtr --group-directories-first
du -sh ~/work/* 2>/dev/null | sort -h
du -sh ~/.[!.]* 2>/dev/null | sort -h | tail -10ls -lhtr:
フォルダの中を一覧で見る。-l は詳しく、-h は大きさを KB・MB で、-t は日付順、-r は逆順(古いものが上)--group-directories-first:
フォルダを先に並べるdu -sh:
フォルダやファイルの大きさを、合計で(-s)、読みやすい単位で(-h)表示するsort -h:
「1.5G」「600M」のような単位つきの大きさを、正しく小さい順に並べる~/.[!.]*:
ホームフォルダの中の、名前が「.」で始まる隠しフォルダ(ただし「..」は除く)tail -10:
最後の10行(=大きいもの上位10)だけを見る
このときは、VS Codeのリモート接続用のフォルダ(.vscode-server)が3.6GBあり、古いバージョンが5つたまっていたことが分かりました。
片付けのコマンド
mkdir -p ~/work/backup ~/work/archive/2026-10
mv wordpress-20261015.sql ~/work/backup/
rm -f wordpress-20261014.sql
rmdir products categories dist apimkdir -p:
フォルダを作る。-p を付けると、途中のフォルダもまとめて作り、すでにあってもエラーにならないmv ファイル 移動先/:
ファイルを移動するrm -f:
ファイルを消す。-f は、確認せずに消す(ファイルがなくてもエラーにしない)。ゴミ箱には入らず、すぐ消えるので注意rmdir:
フォルダを消す。ただし、中身が空のときしか消せない。中に何か入っていればエラーになるので、うっかり消す心配がない
安全に使うために決めていること
シェルのコマンドは、データベースのコマンドと同じく、元に戻すボタンがありません。意味が分かってくると、危ないところも見えてきました。
- 消す前に、一覧を見る:
rm で消す前に、ls や find で、消すものが思ったとおりかを確かめる - 空のフォルダは rmdir で消す:
rm -r は中身ごと消してしまうので、空のはずのフォルダは rmdir で消す。中身があれば止まってくれる - cd してから操作するときは、最初に場所を確かめる:
cd ~/work && … のように && でつなぐと、移動に失敗したときに、続きのコマンドが別の場所で実行されない - 見るだけのコマンドと、変えるコマンドを分ける:
curl、ls、du、find は見るだけなので、何度実行しても大丈夫。mv、rm、データベースの UPDATE などは、確かめてから実行する
まとめ
コピペで動かしていたコマンドも、分けてみると、使っていたのは次の組み合わせでした。
| 目的 | 主なコマンド |
|---|---|
| ページの状態を確かめる | curl(-sI、-o /dev/null -w) |
| 必要な行・部分だけを取り出す | grep(-oE、-iE) |
| くり返す | for、while read |
| 数える・並べる | awk、sort、wc、head、tail |
| ファイルを探す・大きさを調べる | find、du、ls |
| 片付ける | mkdir、mv、rm、rmdir |
それぞれを、パイプ(|)や変数($())でつないでいるだけです。意味が分かると、AIが出したコマンドでも、「このコマンドは見るだけか、何かを変えるのか」「どこを対象にしているのか」を、自分で確かめてから実行できるようになります。
データベースを操作するコマンドは、データベースのコマンドの記事にまとめています。自宅サーバーの構成は、自宅サーバー構築のカテゴリーでまとめています。



コメント