Wargtek
Wargtek

Reputation: 163

Strange bash behaviour (pipe, su, zsh) - Errors in comments and user not changed

I'm writing a script which install and configure users, zsh and zprezto. For my needs, I've written some code that should execute multiple commands as user X (with su) and with zsh shell.

The behaviour is not what I expected so I need some explanations about this code.

su admin -c zsh << EOF
echo '$USER';
echo '$SHELL';
EOF

This code was just for a test : I needed to be sure commands are executed as user admin and in zsh shell. However, output is :

root
/bin/zsh

I just don't understand : shouldn't su change user before executing command ?

I tried writing my code even with this problem and I got another strange behaviour :

cat << EOF | su "admin" -c zsh

local file="${ZDOTDIR:-$HOME}/.zpreztorc"
echo "File for $USER : ${ZDOTDIR:-$HOME}/.zpreztorc"

setopt clobber; # Do not warn when overwritting file
modules=$(cat "$file" | grep -Pzo "(?s)(zstyle ':prezto:load' pmodule\N*.)([\s\t]*'[a-z]*'[\s\t]*\\\\.)*[\s\t]*'[a-z]*'");
firstLineNumber=$(cat "$file" | grep -Fn "$(echo -n "$modules" | head -n 1)" | sed 's/^\([0-9]\+\):.*$/\1/');
lastLineNumber=$(cat "$file" | grep -Fn $(echo -n "$modules" | tail -n 1) | sed 's/^\([0-9]\+\):.*$/\1/');

for module in ${prezto_modules[@]}; do
    modules="$modules \\
  '$module'";
done

fileContent=$(cat "$file" | sed "$firstLineNumber,$lastLineNumber d");

echo -n "$fileContent" | head -n "$((firstLineNumber-1))" > "$file";
echo "$modules" >> "$file";
echo -n "$fileContent" | tail -n "+$((firstLineNumber))" >> $file;

cat "$file";
EOF

However, output is strange too :

cat: '': No such file or directory
cat: '': No such file or directory
cat: '': No such file or directory
grep: loaded: No such file or directory
grep: loaded: No such file or directory
grep: loaded: No such file or directory
grep: loaded: No such file or directory
grep: loaded: No such file or directory
grep: loaded: No such file or directory
grep: loaded: No such file or directory
grep: autoloaded: No such file or directory
grep: autoloaded: No such file or directory
grep: autoloaded: No such file or directory
grep: autoloaded: No such file or directory
grep: autoloaded: No such file or directory
grep: autoloaded: No such file or directory
cat: '': No such file or directory
sed: -e expression n°1, caractère 1: commande inconnue: `,'
tail: incorrect line number: « + »
File for root : /root/.zpreztorc

I tried to translate errors from french, don't know exact traductions for sed so I just let it as is. But errors themselves are not what's strange, look at my first echo line :

echo "File for $USER : ${ZDOTDIR:-$HOME}/.zpreztorc" --> "File for root : /root/.zpreztorc" Except the fact we are root, it's displayed as the last line of output. It means errors are found before executing the code, right ?

Something even more strange : if we comment the code, errors are still noticed :

su "admin" -c zsh << EOF
# modules=$(cat "$file" | grep -Pzo "(?s)(zstyle ':prezto:load' pmodule\N*.)([\s\t]*'[a-z]*'[\s\t]*\\\\.)*[\s\t]*'[a-z]*'");
EOF

The output is :

cat: '': No such file or directory

How could you explain that ? Thanks

Upvotes: 0

Views: 183

Answers (1)

Andreas Louv
Andreas Louv

Reputation: 47099

Here documents with << MARKER will be interpreted as double quotes strings, while << 'MARKER' will be interpreted as single quoted strings:

su admin -c zsh << 'EOF'
  echo "$USER" "this is admin"
EOF

While using << MARKER is expanded before send as stdin

su admin -c zsh << EOF
  echo "$USER" "this is the current user single quotes doesn't prevent it"
  echo '$USER' 'This is still expanded before send as stdin to zsh'
EOF

See man bash | grep --max-count=1 '<<' -A 11 for more information:

          <<[-]word
                  here-document
          delimiter

   No parameter and variable expansion, command substitution,  arithmetic
   expansion, or pathname expansion is performed on word.  If any charac‐
   ters in word are quoted, the delimiter is the result of quote  removal
   on word, and the lines in the here-document are not expanded.  If word
   is unquoted, all lines of the here-document are subjected to parameter
   expansion, command substitution, and arithmetic expansion, the charac‐
   ter sequence \<newline> is ignored, and \ must be used  to  quote  the
   characters \, $, and `.

Upvotes: 2

Related Questions