【问题标题】:How to `cat << 'EOF'` within `su $user <<EOF`?如何在`su $user <<EOF`中`cat <<'EOF'`?
【发布时间】:2021-09-22 16:32:21
【问题描述】:
##!/bin/bash
set -e
backup_dir='/home/my/backup'
user='my'

su $user <<EOFHD
cat << 'EOF' > $backup_dir/autorestartnftables.sh
#!/bin/bash
SERVICENAME="nftables"

# return value is 0 if running
STATUS=$?
if [[ "$STATUS" -ne "0" ]]; then
        echo "Service '$SERVICENAME' is not curently running... Starting now..."
        systemctl start $SERVICENAME
fi
EOF
chmod +x $backup_dir/autorestartnftables.sh
EOFHD

以上脚本用于创建autorestartnftables.sh,预期结果如下:

#!/bin/bash
SERVICENAME="nftables"
# return value is 0 if running
STATUS=$?
if [[ "$STATUS" -ne "0" ]]; then
        echo "Service '$SERVICENAME' is not curently running... Starting now..."
        systemctl start $SERVICENAME
fi

autorestartnftables.sh 运行后sudo bash ./example.sh:

#!/bin/bash
SERVICENAME="nftables"
# return value is 0 if running
STATUS=0
if [[ "" -ne "0" ]]; then
        echo "Service '' is not curently running... Starting now..."
        systemctl start 
fi

问题出在哪里?

【问题讨论】:

  • 以当前用户的身份写入文件,然后使用susudo 将文件移动到位,而不是尝试嵌套此处的文档,这会简单得多。这里一个可能的问题是$?(例如)作为外部文档创建的一部分进行了扩展;它不受引用的内部文档的保护。
  • @chepner,我的问题中的脚本实际上是 bash 脚本的一部分,我只想在没有更多 sudo 的情况下这样做。
  • 那么您将逃脱您认为'EOF' 正在逃脱的一切。
  • 我想知道除了echo,cat &lt;&lt; EOF之外的其他东西。

标签: bash sudo eof cat su


【解决方案1】:

不要筑巢、筑巢、筑巢。而是使用declare -f 和函数将工作转移到不相关的上下文中。

##!/bin/bash
set -e
backup_dir='/home/my/backup'
user='my'
work() {
    cat << 'EOF' > $backup_dir/autorestartnftables.sh
#!/bin/bash
SERVICENAME="nftables"

# return value is 0 if running
STATUS=$?
if [[ "$STATUS" -ne "0" ]]; then
        echo "Service '$SERVICENAME' is not curently running... Starting now..."
        systemctl start $SERVICENAME
fi
EOF
    chmod +x $backup_dir/autorestartnftables.sh
}
su "$user" bash -c "$(declare -p backup_dir); $(declare -f work); work"

在这种情况下,您可以检查运行脚本的用户是否是您想要的用户,然后使用该用户重新启动脚本:

##!/bin/bash
set -e
backup_dir='/home/my/backup'
user='my'
if [[ "$USER" != "$user" ]]; then
   # restart yourself as that user
   exec sudo -u "$user" "$0" "$@"
fi

cat << 'EOF' > $backup_dir/autorestartnftables.sh
#!/bin/bash
SERVICENAME="nftables"

# return value is 0 if running
STATUS=$?
if [[ "$STATUS" -ne "0" ]]; then
        echo "Service '$SERVICENAME' is not curently running... Starting now..."
        systemctl start $SERVICENAME
fi
EOF
chmod +x $backup_dir/autorestartnftables.sh

用 shellcheck 检查你的脚本。

【讨论】: