sed を使用してリスト変数から行を削除する

sed を使用してリスト変数から行を削除する

ループ内で sed を使用してリストから単語を含む行を削除するスクリプトがあります。

for i in $list; do
  sed -i "/$i/d" file
done

$listSQL クエリから作成されます:

list=$(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")

問題は、私の会社が最近、すべてのfchownまたはfchmodsyscalls を含む、より厳しい監査ルールを実装したことです。 を使用すると、 every に1 つのおよびsyscall が含まれているstraceことがわかります。sed -ifchownfchmod

リスト変数が大きい場合、iowaitauditd が膨大な量の行をログに書き込むため、負荷が急上昇し、システムが実際に停止します。

リスト変数を sed に 1 行で渡して、ファイルが 1 回だけ開かれて閉じられるようにする方法があるかどうかを調べています。

すでに質問しましたが、監査ルールを変更することは不可能です。

ありがとう。

答え1

膨大な数のインライン コマンドを 1 つずつ呼び出すのではなく、1 回だけ実行しsedて単一のスクリプトを使用することで、次のことが可能になります。sed

sedscript=$(mktemp)
for i in $list; do
  echo "/$i/d" >> "$sedscript"
done
sed -f "$sedscript" -i /path/to/file
rm -f "$sedscript"

答え2

内の単語を注意深く割り当てることができればlist、bash パラメータ展開を使用してすべてのスペースを正規表現オルタネータ に置き換え|grepask にその作業を実行させることができます。

list='auditd the to'
cp file temp &&  
grep -Ev "${list// /|}" temp > file && 
rm temp 

答え3

シェルが配列をサポートしている場合は、次のようにします。

mapfile -t arr < <(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")

コマンドの出力をシェル配列に格納するには、

printf '/%s/d\n' "${arr[@]}" | sed -i.bak -f - somefile

削除シーケンスを に適用しますsomefile。コマンドから返されるフィールドpsqlに に固有の文字が含まれている可能性がある場合は、通常の注意事項が適用されますsed

これは @DopeGhoti のソリューションに似ていますが、一時スクリプト ファイルを回避する点が異なります (必要に応じてテーブル フィールドの空白を処理する必要があります)。

答え4

次のようにすると、psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC"空白で区切られた単語のリストが表示される場合は、次を試してください。

$ psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC" \
| awk -v FS=" " -v OFS="|" '{$1=$1; print "("$0")"}' \
| xargs -I {} sed -i -E '/{}/d' file

関連情報