特定の文字列を含む行をコマンドで削除

sed等で特定の文字列を含む行を削除したい場合、含まれている文字によっては期待通りの動作にならずにただただ試行錯誤して無駄に時間が過ぎ去っていくこともあります。悲しいですね。

例えば、URLが複数行あるリストを読み込み、アクセスできない行を削除したいという場合。

sedだと通常使用する「/」(スラッシュ)はURL「https://~」となるため、使用できません。

別の文字、例えば「#」等でも代替可能なはずですが、何故か行を削除するという期待の動作になってくれません。

リストから読み込むので変数での処理となるため、「’」(シングルクォート)での指定もできません。

いや、もしかすると回避する方法は存在するのかもしれませんが、似たような状況のたびに調べつくしたり、結果バージョンによる差異で動作したりしなかったりするのでは使い勝手が悪いです。

そのため、特定の文字列を含む行を削除したい場合は頭を空っぽにして「grep」を使用した方が効率的です。

神「sedに拘るのはやめて、grepを使用しなさい」

下僕「はい」

sedではなくgrepの除外なんかでいいんですか?いいんです。

本題に移りますが、sedだと通常は

sed -i '/指定文字列/d' list.txt

などとして指定文字列の行を削除しますが、リストにあるURLの変数を含む行を削除したい場合だと

sed -i "#${line}#d" list.txt

等としたくなるではないですか。私はしたいです。

でも、残念ながらそれだと通らない。通りません。

実際には何も削除されません。

そこで、「grep -v」で除外したものをリダイレクトさせて上書き、結果として同じ動作をさせます。

(rm -f ${list_file} && grep -v "${line}" > ${list_file}) < ${list_file}

では、URLが複数行あるリストを読み込み、アクセスできない行を削除したい場合のスクリプトを参考までに。

【参考】URLが複数行あるリストを読み込み、アクセスできない行を削除したい場合のスクリプト

#!/bin/sh
list_file=/tmp/list.txt
while read line
do
  CT=$(wget -q -O - ${line} | wc -l)
  if [ "${CT}" -eq "0" ];then
    (rm -f ${list_file} && grep -v "${line}" > ${list_file}) < ${list_file}
  fi
done <${list_file}

コメントは受け付けていません。