[PR] 本記事にはプロモーションが含まれています。

【bash】コピペで動かしていたサイトの確認・片付けのコマンドを、意味から理解する|curl・for・find・du

自宅サーバー構築
➔ 自宅サーバー構築メモの目次はこちら

【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 を付けていました。

Bash
sudo -v
  • sudo -v:
    先に管理者のパスワードを聞いておく命令。長いコマンドの途中で sudo のパスワードを聞かれると、結果の表示が途中で止まって見えることがあるので、最初に実行しておく

場面1:ページが転送されているか、なくなっているかを確かめる

記事を消したり、URLを変えたりしたときは、古いURLがちゃんと新しいURLへ転送(301)されているかを確かめていました。

Bash
curl -sI https://softdev-learn.cc/ts-express-api-step7-git/ | grep -iE "^(HTTP|location)"

結果の例:

Plaintext
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のままになっていたことも、このコマンドで気づけました。

数字だけを出す

数字だけが欲しいときは、次の形にしました。

Bash
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回で確かめたのが次のコマンドです。

Bash
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

結果の例:

Plaintext
旧 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本だけ転送のルールを追加しました。

公開後のチェックをまとめて行う

記事を公開したあとの確認も、同じ部品の組み合わせで、まとめて行いました。

Bash
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 で確かめています。

Bash
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/"
done
  • sudo 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:数えて、多い順に並べる

代替テキストが空の画像が、どの記事に何枚あるかを数えたときのコマンドです。

Bash
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を超える大きな画像を探したときのコマンドです。

Bash
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:フォルダの容量を調べて、片付ける

作業用のフォルダが散らかってきたときに、何がどれだけ場所を取っているかを調べました。

Bash
cd ~/work && ls -lhtr --group-directories-first
du -sh ~/work/* 2>/dev/null | sort -h
du -sh ~/.[!.]* 2>/dev/null | sort -h | tail -10
  • ls -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つたまっていたことが分かりました。

片付けのコマンド

Bash
mkdir -p ~/work/backup ~/work/archive/2026-10
mv wordpress-20261015.sql ~/work/backup/
rm -f wordpress-20261014.sql
rmdir products categories dist api
  • mkdir -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が出したコマンドでも、「このコマンドは見るだけか、何かを変えるのか」「どこを対象にしているのか」を、自分で確かめてから実行できるようになります。

データベースを操作するコマンドは、データベースのコマンドの記事にまとめています。自宅サーバーの構成は、自宅サーバー構築のカテゴリーでまとめています。

コメント