使用sed处理passwd文件

Mat*_*att 2 bash sed

我正在尝试学习 sed,但遇到了很多麻烦。我想要做的是使用带有 sed 命令的 bash 脚本处理我的 passwd 文件以执行以下操作:对于组 ID 为 20000 的每个用户,将文件中的 GID 替换为 2000x,其中 x 是第一个字母的顺序用户的用户名(即:a 为 1,b 为 2 等)此外,对于默认 shell 为 bash 的每个用户,将其组更改为 bash,对于那些使用 shell 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
Run Code Online (Sandbox Code Playgroud)

理想情况下,我会选择每行的第 4 个字段来获取 shell 的组 ID 和第 7 个字段,但同样,我不知道在 sed 中执行此操作的方法。提前致谢。

Gil*_*il' 6

awk 真的是这里的自然工具:/etc/passwd由冒号分隔的字段组成,每一行都具有相同的布局,这正是 awk 用来解析的。

如果要使用 sed,基本思想是将每个字段捕获在一个带括号的组中,并使用反向引用来引用每个字段的内容。例如,这里是如何将用户的 shell 更改为 zsh 之前它是 bash。

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

我用作~分隔符;通常使用/,但您可以使用其他字符,并且/在模式中出现时使用不同的字符更方便。~#!是常见的选择;为了您的理智,不要选择在正则表达式中具有特殊含义的字符。

正则表达式包含 6 个\([^:]*\):,它匹配一个字段(除 之外的字符序列:)和一个字段分隔符。为方便起见,我将每个字段放在一个单独的组中。由于前 6 个字段不会改变,我可以将它们全部放在一个组中,甚至最后一个字段的开头也不会改变。

sed 's~^\([^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:/bin/\)bash$~\1zsh~'
Run Code Online (Sandbox Code Playgroud)

此外,由于字段数是固定的,shell是最后一个字段,我们不需要计算字段数。所以我们可以用更简单但不太清楚的方式来编写这个程序:

sed 's~^\(.*:/bin/\)bash$~\1zsh~'
Run Code Online (Sandbox Code Playgroud)

或者我们可以删除^并只替换该行的最后一部分。

sed 's~:/bin/bash$~:/bin/zsh~'
Run Code Online (Sandbox Code Playgroud)

请注意,这种临时简化可以使正则表达式更清晰,同时使意图不那么明显。

当您需要对符合特定条件的行进行操作时,有两种基本方法。一种是匹配整条线并使用分组将其分成几部分,就像我们上面所做的那样。另一种方法是将s命令限制为匹配特定模式的行。当条件与模式替换没有直接关系时,第二种方法更具可读性。这是基于此原则的示例:对于默认 shell 为 bash 的每个用户,将其组更改为 2981。

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

如果要进行多个替换,则可以使用多个命令:将每个命令作为参数传递给-e选项。(大多数 sed 实现还允许使用换行符分隔命令的单个参数;其中一些还允许使用分号作为命令分隔符。)请注意,这些命令依次应用于每一行,因此第一个命令的结果与第二个命令匹配.

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