奇怪的 bash 行为(管道、su、zsh)- 评论错误和用户未更改

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

我正在编写一个脚本来安装和配置用户、zsh 和 zprezto。为了我的需要,我编写了一些代码,应该以用户 X(使用 su)和 zsh shell.

执行多个命令

行为不是我所期望的,所以我需要一些关于这段代码的解释。

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

此代码仅用于测试:我需要确保命令以用户管理员身份和 zsh shell 中执行。但是,输出是:

root
/bin/zsh

我只是不明白:su 不应该在执行命令之前更改用户吗?

即使有这个问题,我也尝试编写我的代码,但我遇到了另一个奇怪的行为:

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]\+\):.*$//');
lastLineNumber=$(cat "$file" | grep -Fn $(echo -n "$modules" | tail -n 1) | sed 's/^\([0-9]\+\):.*$//');

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

然而,输出也很奇怪:

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

我试图翻译法语中的错误,不知道 sed 的确切翻译,所以我就按原样翻译。 但是错误本身并不奇怪,看看我的第一个回显行:

回声"File for $USER : ${ZDOTDIR:-$HOME}/.zpreztorc" --> "File for root : /root/.zpreztorc" 除了我们是 root 之外,它显示为输出的最后一行。这意味着在执行代码之前发现错误,对吗?

更奇怪的是:如果我们注释代码,错误仍然存​​在:

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

输出是:

cat: '': No such file or directory

你怎么解释? 谢谢

此处带有 << MARKER 的文档将被解释为双引号字符串,而 << 'MARKER' 将被解释为单引号字符串:

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

虽然使用 << MARKER 在作为标准输入发送之前被扩展

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

有关详细信息,请参阅 man bash | grep --max-count=1 '<<' -A 11

          <<[-]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 `.