Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Total newbie to shell scripting, I am searching to create a script to automatically apply some custom configuration to text based configuration files.

In the present case, I am searching to add 2 line to /etc/sysctl.conf if these line are not yet in the file (to avoid having multiple occurrence of these line in the file).

here is the script I use :

if [ `grep vm.swappiness /etc/sysctl.conf` != "vm.swappiness=5" ]; then
echo vm.vfs_cache_pressure=50 | sudo tee -a /etc/sysctl.conf
fi
if [ `grep vm.vfs_cache_pressure /etc/sysctl.conf` != "vm.vfs_cache_pressure=50" ]; then
echo vm.vfs_cache_pressure=50 | sudo tee -a /etc/sysctl.conf
fi

and the error I get :

/home/erwan/Workspace/Install.sh: ligne 19 : [: != : opérateur unaire attendu
/home/erwan/Workspace/Install.sh: ligne 23 : [: != : opérateur unaire attendu

What am I doing wrong?

share|improve this question
    
FYI it's not Linux scripting, it's shell scripting, or (e.g.) bash scripting. –  goldilocks Jun 23 at 14:35

4 Answers 4

up vote 6 down vote accepted

This is a problem:

if [ `grep vm.swappiness /etc/sysctl.conf` != "vm.swappiness=5" ]; then

Since if grep doesn't find anything, it doesn't output anything, and the left hand side of this will be nothing, which is an error. It's also a problem if it does find something, since the output could contain whitespace (e.g., if vm.swappiness is in the file multiple times). That needs to be quoted, or it will appear as a series of distinct strings when expanded.

You should thus use if [ "$(grep ...)" ] so the output is quoted. If there is no output, you have "", which is fine on either side of a test in bash.

However, in this case I'd recommend using the exit status of grep instead. From man grep:

EXIT STATUS

Normally, the exit status is 0 if selected lines are found and 1 otherwise. But the exit status is 2 if an error occurred...

Also usefule here is the -q switch:

-q, --quiet, --silent

Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected.

So, keeping in mind $? is the exit status of the last completed foreground process:

grep -q grep vm.vfs_cache_pressure /etc/sysctl.conf
if [ $? -eq 1 ]; then

This condition will be true if grep did not find anything, and no error occurred.

share|improve this answer
2  
if works on the command directly, so you can even just write it as if ! grep -q not_found /etc/sysctl.conf; then ...;fi. –  h.j.k. Jun 24 at 2:06
    
@h.j.k The problem with that here is that the test is actually to see if grep failed to find anything -- but we also want to exclude fail on error...in the former case it returns 1, in the later 2. We want only the former. I.e. it's "if grep did not encounter errors or find a match". Going that route, it might be good to use a case or elif to report any errors. –  goldilocks Jun 24 at 10:27
    
ah I see, that's clearer and makes sense now. Thanks for the explanation! –  h.j.k. Jun 24 at 12:11

It could be because your grep is not returning anything. As it isn't quoted, then you get that error message (unary operator expected). Try:-

if [ "$(grep vm.swappiness /etc/sysctl.conf)" != "vm.swappiness=5" ]; then
share|improve this answer
    
It worked, but goldilocks explained it better. I give you an upvote anyway –  Dremor Jun 23 at 14:56

Just for inspirational purposes, needs some tweaking maybe:

#assuming there is only one line with vm.swappiness
#otherwise you can use the test command with "grep -c vm.swappiness" first
#tests if the correct line is in the file
if grep -q -E '^vm.swappiness=5$' /etc/sysctl.conf; then
    echo "all good, do nothing";
else
    echo "removing possible lines with vm.swappiness"
    sudo sed -i '/^vm.swappiness=/d' /etc/sysctl.conf 
    echo "adding line with correct swappiness"
    sudo bash -c "echo 'vm.swappiness=5' >> /etc/sysctl.conf"
fi

Also wrapping this in a function might be good, so you can call it with your next parameter too.

share|improve this answer

This would probably work:

f=/etc/sysctl.conf
[ -w "$f" ] || exit 1
for line in 'vm.swappiness=5' 'vm.vfs_cache_pressure=50' ; do
    grep -q "$line" <"$f" || printf %s\\n "$line"
done >>"$f"

You should probably get sudo out of that script, too. If needed run the script with sudo like sudo ./script.sh and keep it as a separate module from other scripts. Else do:

sudo sh -c '
    f=/etc/sysctl.conf
    [ -w "$f" ] || exit 1
    for line in "vm.swappiness=5" "vm.vfs_cache_pressure=50" ; do
        grep -q "$line" <"$f" || printf %s\\n "$line"
    done >>"$f"
'

But I don't recommend it.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.