Bash awk command with quotes

bashscriptingshell

I have been trying to find the answer to this question for a while. I am writing a quick script to run a command based on output from awk.

ID_minimum=1000
for f in /etc/passwd;
do 
    awk -F: -vID=$ID_minimum '$3>=1000 && $1!="nfsnobody" { print "xfs_quota -x -c 'limit bsoft=5g bhard=6g $1' /home "}' $f;       
done

The problems are that the -c argument takes a command in single quotes and I can't figure out how to properly escape that and also that $1 doesn't expand into the username.

Essentially I am just trying to get it to output:

xfs_quota -x -c 'limit bsoft=5g bhard=6g userone' /home
xfs_quota -x -c 'limit bsoft=5g bhard=6g usertwo' /home

etc…

Best Answer

To run the command xfs_quota -x -c 'limit bsoft=5g bhard=6g USER' /home for each USER whose UID is at least $ID_minimum, consider parsing out those users first and then actually run the command, rather than trying to create a string representing the command that you want to run.

If you create the command string, you would have to eval it. This is fiddly and easy to get wrong. It's better to just get a list of usernames and then to run the command.

getent passwd |
awk -F: -v min="${ID_minimum:-1000}" '$3 >= min && $1 != "nfsnobody" { print $1 }' |
while IFS= read -r user; do
    xfs_quota -x -c "limit bsoft=5g bhard=6g $user" /home
done

Note that there is no actual need for single quotes around the argument after -c. Here I use double quotes because I want the shell to expand the $user variable which contains values extracted by awk.

I use ${ID_minimum:-1000} when giving the value to the min variable in the awk command. This will expand to the value of $ID_minimum, or to 1000 if that variable is empty or not set.


If you really wanted to, you could make the above loop print out the commands instead of executing them:

getent passwd |
awk -F: -v min="${ID_minimum:-1000}" '$3 >= min && $1 != "nfsnobody" { print $1 }' |
while IFS= read -r user; do
    printf 'xfs_quota -x -c "limit bsoft=5g bhard=6g %s" /home\n' "$user"
done

Note again that using double quotes in the command string outputted (instead of single quotes) would not confuse a shell in any way if you were to execute the generated commands using eval or though some other means. If it bothers you, just swap the single and double quotes around in the first argument to printf above.

Related Question