Reputation: 6163
I want to write a bash script which can update the /etc/security/limits.conf
file.
The file could contain something like:
* soft core 0
* hard rss 10000
@student hard nproc 20
@faculty soft nproc 20
@faculty hard nproc 50
ftp hard nproc 0
@student - maxlogins 4
Let's say I want to run the script like so:
Usage:
update-ulimits <domain> <type> <item> <value>
Examples:
./update-ulimits '*' hard rss 20000
./update-ulimits bob hard nofile 1024
Which would change the file to contain:
* soft core 0
* hard rss 20000
@student hard nproc 20
@faculty soft nproc 20
@faculty hard nproc 50
ftp hard nproc 0
@student - maxlogins 4
bob hard nofile 1024
So if the file already contains a line which has the domain
, type
and item
it would replace the value
, otherwise it will append a new line containing all 4 arguments. The columns do not need to be aligned.
This is a specific example where there are only a couple of meta characters to worry about but I'm curious whether there is a nice solution which could handle all arbitrary meta characters. I'm guessing perl and awk should be able to do it but I am not too familiar with either.
Upvotes: 1
Views: 87
Reputation: 5251
This is not a good idea. How do you select which line to edit?The only real way to do this is to specify a match expression, and then a substitution line/fields. Even then, you may have multiple matches.
A quicker approach is to just print each lines w/ numbers, and have the user select a line to edit. At that point, you may as well just open it in a text editor.
My advice is to learn sed
and awk
. Then, whenever you need to do a specific editing job on the file, you can.
EDIT - If you just want to replace a value:
sed -E s'/(^<match-fields>\s+)([0-9]+\s*$)/\1<new-number>/'
Upvotes: 0
Reputation: 35246
One awk
solution:
$ cat update-ulimits
#!/usr/bin/bash
domain="${1}" # OP can add code to verify inputs as needed
ltype="${2}"
item="${3}"
value="${4}"
awk -v dom="${domain}" -v type="${ltype}" -v item="${item}" -v val="${value}" '
($1 == dom) &&
($2 == type) &&
($3 == item) { $4 = val ; foundit=1 } # overwrite field 4
{ print } # print current line
END { if (! foundit) { print dom, type, item, val } } # if not found, print all inputs as a new line
' limits.conf
A couple sample runs:
$ update-ulimits '*' hard rss 20000
* soft core 0
* hard rss 20000
@student hard nproc 20
@faculty soft nproc 20
@faculty hard nproc 50
ftp hard nproc 0
@student - maxlogins 4
$ update-ulimits bob hard nofile 1024
* soft core 0
* hard rss 10000
@student hard nproc 20
@faculty soft nproc 20
@faculty hard nproc 50
ftp hard nproc 0
@student - maxlogins 4
bob hard nofile 1024
NOTES:
awk
should automatically overwrite the source file (see the -i
flag, eg: Save modifications in place with awk ) or perhaps add additional code to first save the original file before overwriting it.limits.conf
I took the easy way out and didn't bother with maintaining whitespace for modified lines; if maintaining original white space is desired take a look at the answers to How to preserve the original whitespace between fields in awk?.Upvotes: 2