sedを使用したpasswdファイルの処理

sedを使用したpasswdファイルの処理

sedを学ぼうとするのに悩みが多いです。私が望むのは、sedコマンドでbashスクリプトを使用して私のpasswdファイルを処理することです。グループIDが20000のユーザーごとに、ファイルのGIDを2000xに置き換えます。ここで、xは最初です。ユーザーのユーザー名のアルファベット順に(たとえば、aは1、bは2など)、デフォルトのシェルがbashの各ユーザーの場合はグループをbashに変更し、tcshシェルを使用する各ユーザーの場合はそのグループをtcshgroupにします。変更します。私はawkで上記のことをしましたが(使いやすいと思います)、sedをどこで始めるべきかさえわかりません。どんな助けでも大変感謝します。

これはpasswdファイルの一部です:

speech-dispatcher:x:108:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
colord:x:109:117:colord colour management daemon,,,:/var/lib/colord:/bin/false
lightdm:x:110:118:Light Display Manager:/var/lib/lightdm:/bin/false
avahi:x:111:120:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
hplip:x:112:7:HPLIP system user,,,:/var/run/hplip:/bin/false
pulse:x:113:121:PulseAudio daemon,,,:/var/run/pulse:/bin/false
saned:x:114:20000::/home/saned:/bin/tcsh
mmccormick:x:1000:20000:owner,,,:/home/mmccormick:/bin/bash

理想的には、各行のフィールド4を選択してシェルのグループIDとフィールド7を取得しますが、sedでこれを行う方法を知りません。よろしくお願いします。

ベストアンサー1

awkはここで本当に自然なツールです。/etc/passwdコロンで区切られたフィールドで構成され、各行は同じレイアウトを持ち、これはawkが解析用に作成されたものです。

sed を使用する場合、デフォルトのアイデアは角かっこグループの各フィールドをキャプチャし、逆参照を使用して各フィールドの内容を参照することです。たとえば、ユーザーのシェルをzsh(以前のbash)に変更する方法は次のとおりです。

sed 's~^\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):/bin/bash$~\1:\2:\3:\4:\5:\6:/bin/zsh~'

区切り文字として主に使用しますが~、別の文字を使用してもよく、/パターンに現れるときは別の文字を使用する方がより便利です。または一般的な選択です。正規表現で特別な意味を持つ文字を選択しないでください。/~#!

この正規表現には6番が含まれ、\([^:]*\):フィールド(を除く一連の文字:)とフィールド区切り文字と一致します。便宜上、各フィールドを別々のグループに配置します。最初の6つのフィールドは変更されないため、すべて1つのグループに配置でき、最後のフィールドの先頭も変更されません。

sed 's~^\([^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:/bin/\)bash$~\1zsh~'

また、フィールド数は固定され、シェルは最後のフィールドなので、フィールド数を数える必要はありません。したがって、私たちはこのプログラムをよりシンプルで明確な方法で書くことができます。

sed 's~^\(.*:/bin/\)bash$~\1zsh~'

あるいは、^行の最後の部分だけを削除して置き換えることもできます。

sed 's~:/bin/bash$~:/bin/zsh~'

これらの一時的な単純化により、正規表現をより明確にし、意図を明確にすることができません。

特定の基準を満たす回線で作業する必要がある場合は、2つの基本的なアプローチがあります。 1つは、上記のようにライン全体を一致させ、グループ化を使用して複数の部分に分割することです。別のアプローチは、s特定のパターンに一致する行にコマンドを制限することです。第2のアプローチは、条件がパターン置換と直接関係しない場合、より読みやすくなる。以下は、この原則に基づく例です。デフォルトのシェルがbashの各ユーザーに対して、そのグループを2981に変更します。

sed '/:\/bin\/bash$/ s~^\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\)$~\1:\2:\3:2981:\5:\6:\7'

複数の置換を実行するには、複数のコマンドを使用できます。各コマンドをoptionsに引数として渡します-e。 (ほとんどのsed実装では、改行によってコマンドの個々のパラメータを区別することもできます。一部の実装ではセミコロンをコマンド区切り文字として受け入れることもあります。)これらのコマンドは各行に順番に適用されるため、最初のコマンドの結果は次のようになります。と同じです。 2番目のコマンドが一致します。

sed -e '/:\/bin\/bash$/ s~^\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\)$~\1:\2:\3:2981:\5:\6:\7' \
    -e '/:\/bin\/tcsh$/ s~^\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\)$~\1:\2:\3:1989:\5:\6:\7' \

おすすめ記事