I want to make echo from one script to another script, but I don't want to get the output of the command because I want to use this command in another script, I need to create a script that creates the adduser.local script for me.

The first script is:

sudo echo "
'lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"' " >>

and what I get from /usr/local/sbin/adduser.local is the output of the command, and I want to copy the command as is because I don't want to get the output in the first script I want to get the output in the second script. So I need to know how to use the echo right that the first script drops the command as is to adduser.local.

The adduser.local script needs to look like this after the first run

lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"
#and now i can use the $lastuser in this script
echo " '$lastuser' ALL = !/usr/bin/apt-get update " >> /etc/sudoers

You likely shouldn't do that. You can probably achieve your goal in way that does not involve writing one script that generates another script that you will later modify and run; see below. But if you really want to do it, and you want to do it with code that closely resembles what you've shown, then steeldriver is right that a here document is a workable way.

The way steeldriver uses a here document is fine; here's another, whose code is a bit simpler. (I'm presenting it mainly for the opportunity to explain the meaning of each part of its syntax, not out of the belief that this approach is superior.)

cat >/usr/local/sbin/adduser.local <<'EOF'
lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"

Replace /usr/local/sbin/adduser.local with whatever name you want for the second script, if it is different. Then simply run the script as root, for example with sudo. The entire point of this script is to create a file in a location only root has write access to, so it is itself the sort of command that makes sense to run as root with sudo. When you have a script in which every command starts with sudo (especially if it's a one-command script), that often suggests that the script shouldn't use sudo inside of it at all but should instead just be run with sudo.

Depending on how you're running the generated script, you may need to give it execute permissions, which you can do with chmod +x. (That applies to steeldriver's way, as well.) If the file already exists and has execute permissions, and you're overwriting it, then you don't need to run chmod.

The way the command shown above works is that:

  • When cat is run with no filename arguments (as is the case here), it simply copies its input to its output.
  • cat's output is redirected to the file /usr/local/sbin/adduser.local by the output redirection operator >. I've used the > operator, which overwrites, even though you were using >>, which appends. I'm doing this because I assume you want to overwrite that file, because the text you're placing in it starts with a hashbang, which doesn't usually make sense except at the beginning of a file.
  • cat's input is taken from the text that appears on the following line, up to but not not including any of the line that begins with EOF, stipulated by the here document notation <<.
  • Quoting EOF after << -- that is, writing <<'EOF' rather than <<EOF -- suppresses expansions in the body of the here document, so that none of the characters in the bash code there are treated specially by the shell running the first script.

Using a here document eliminates difficulties associated with quotes that are nested inside other quotes. If you ever need the body of a here document to contain EOF, that's fine, because although EOF is one of the popular choices of word, it's not special at all. You can use whatever word you like. Just use it both after << and at the beginning of a line that appears by itself after the last line you wish to provide as input--just as EOF is used above.

There are several reasons you should probably not actually do that (nor use any echo-based method) in the situation you appear to be describing.

First, if your goal is to allow non-root users to install updates, editing sudoers might not be the best way to achieve that. There are other approaches; for example, you can schedule updates for automatic unattended installation or let non-root users use the update manager and you may be interested in this technique or some variation on it. I'm not sure quite what your requirements are, but you might want to ask about whatever specific problem you're trying to solve.

Second, if you do end up editing /etc/sudoers, it's usually bad to do so in a way that does not involve automatically checking for syntax errors and rejecting modifications that introduce them. (It is also often better to create or edit a sudoers file in the /etc/sudoers.d directory rather than modifying the main sudoers file /etc/sudoers, but the same cautions and considerations apply.) When you manually edit a sudoers file with the visudo command, such checks are performed; the file you're editing is not a real sudoers file, but is instead a temporary file that is checked and only copied over to a real sudoers file after passing syntax checks.

The slightest syntax error in any sudoers file causes sudo to refuse to allow anyone to perform actions as root! This is often easy to fix, but if the reason you're not using a Polkit-based approach is that this is a server system without Polkit, then it's a bit harder. If you must edit a sudoers file not through visudo, you can take the precautionary measure of opening a root shell, separate from the shell in which you're running the commands that modify your configuration, such as by running sudo -i. Once started, this will remain usable, for as long as it is running, even if sudo is broken.

You can actually use visudo to check the syntactic correctness of automated, scripted modifications to sudoers files! This is possible because it accepts any command as the text editor to use to edit the file; this can be customized for a single run of visudo using the SUDO_EDITOR environment variable, and you can write a script that behaves as that editor but is automated and requires no interactions (except perhaps in the event that it produces a syntax error that visudo blocks). I'd consider the details beyond the scope of this answer; if you want help doing something like that, you could ask another question about it.

Third, it looks like you're planning to add several (perhaps many) entries to a sudoers file, for individual users. If so, you should consider adding a single entry for a group and adding the users to the group. This is the approach used to allow administrators on an Ubuntu system to run arbitrary commands as root with sudo; such users are members of the sudo group, which /etc/sudoers has an entry for. You can create other groups and give them other permissions, which can be more restrictive than the ability the sudo group has to run arbitrary commands.

Fourth, even if you do want to follow the approach you're taking, there are better ways than having one script embed a fragment that it uses to seed other scripts that you manually modify. The two approaches I suspect you might find most useful are:

  • You can put lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)" in a file, which need not be executable nor start with a #! hashbang line, and then source that file in whatever scripts are going to use lastuser, by having those scripts contain the command . lastuser.sh (or source lastuser.sh, which is equivalent in bash), where lastuser.sh is the name of the file that contains the command. The lastuser variable gets defined at the time the . lastuser.sh command runs, so it will still always depend on the current state of /etc/passwd.
  • If you really do want one script to create another, then rather than embedding the code that will be copied into the first script, you can make a master file that contains it have the first script just copy that file to the desired location. You could do the copying with cp or install.
  • Thank you very much. I understand my mistakes, and I think I will create a group in the sudoers file and in the adduser.local I will write command that adds the new user to the group what you think about it? – pisoto Jul 11 at 22:35

Use a here document, making sure to quote the delimiter word so that the shell does not expand anything in the body:


cat << 'EOF' | sudo tee -a /usr/local/sbin/adduser.local
lastuser="$(grep home /etc/passwd | cut -d: -f 1 | tail -1)"

The use of tee is because sudo echo "..." >> somefile doesn't do what you think it does - see How to solve “permission denied” when using sudo with redirection in Bash?

  • thx its works for me. – pisoto Jul 11 at 21:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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