shell systemd用户服务的Bash损坏管道错误

z6psavjg  于 2023-05-18  发布在  Shell
关注(0)|答案(1)|浏览(153)

我有bash脚本,应该执行,当特定的设备连接。当我从终端启动它时,我没有得到任何问题,但是,当我启动它作为systemd服务时,我得到了管道破裂错误。

мая 07 10:47:49 nixos systemd[1563]: Starting garmin.service...
мая 07 10:47:51 nixos bash[6951]: grep: ошибка записи: Broken pipe
мая 07 10:47:51 nixos systemd[1563]: garmin.service: Control process exited, code=exited, status=127/n/a
мая 07 10:47:51 nixos systemd[1563]: garmin.service: Failed with result 'exit-code'.
мая 07 10:47:51 nixos systemd[1563]: Failed to start garmin.service.

这是我的systemd服务:

[Unit]
After=run-media-serg-GARMIN.mount
Requires=run-media-serg-GARMIN.mount

[Service]
Environment="LOCALE_ARCHIVE=/nix/store/ckkhm153z75sw6z5nr277kvn2pi4z8jy-glibc-locales-2.35-224/lib/locale/locale-archive"
Environment="PATH=/nix/store/l6jgwxkc3jhr029vfzfwzcy28iyckwsj-coreutils-9.1/bin:/nix/store/gn1s1s5z19cf0wiir2cd38jckcjc6kn6-findutils-4.9.0/bin:/nix/store/pvb117r7fhwb08717ks21a6y9hlnp63b-gnugrep-3.7/bin:/nix/store/v0hg83sdv4v51c0prmdigry6wdmmpzmp-gnused-4.8/bin:/nix/store/34am2kh69ll6q03731imxf21jdbizda2-systemd-251.15/bin:/nix/store/l6jgwxkc3jhr029vfzfwzcy28iyckwsj-coreutils-9.1/sbin:/nix/store/gn1s1s5z19cf0wiir2cd38jckcjc6kn6-findutils-4.9.0/sbin:/nix/store/pvb117r7fhwb08717ks21a6y9hlnp63b-gnugrep-3.7/sbin:/nix/store/v0hg83sdv4v51c0prmdigry6wdmmpzmp-gnused-4.8/sbin:/nix/store/34am2kh69ll6q03731imxf21jdbizda2-systemd-251.15/sbin"
Environment="TZDIR=/nix/store/z0kg1c0f8fx6r4rgg5bdy01lb2b9izqg-tzdata-2023a/share/zoneinfo"

ExecStart=/nix/store/kga2r02rmyxl14sg96nxbdhifq3rb8lc-bash-5.1-p16/bin/bash -c /nix/store/jqfh2bnzag50wlghwnw52mq2nzr8bzz2-garmin-backup/bin/garmin-backup
Type=forking

这是我的剧本:
简而言之,它会检查是否安装了正确的设备,然后用rsync同步一些文件夹,并发送通知和写日志。

#!/usr/bin/env bash

backupDir="/home/serg/Backup/Garmin Edge 830/"
#I need to export this variables for notify-send
export DISPLAY=:0 
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus

on_error() 
{
     _MSG_=$1
     echo "$_MSG_"
     exit 1
}

check_mount()
{
    _MOUNT_=$1
    _MSG_=$2
    
    if [ ! -d "$_MOUNT_" ]; then
        echo "Path to $_MSG_ mount point is not exists"
        exit 1
    fi
}

writeLog() 
{
    _LOG_=$1
    _SAVE_PATH_=$2

    local outputPath="$_SAVE_PATH_/backup_history_${_LOG_}".log

    if [ ! -e "$outputPath" ]; then
        echo "Backup_log: " > "$outputPath"
    fi
    date >> "$outputPath"
}

garmin()
{
    mpointGarmin="$(df -h | grep -i "Garmin" | awk '{print $NF}')"

    check_mount "${mpointGarmin}" "Garmin"
    
    inputDir="${mpointGarmin}/Garmin/"
    copyArray=(
            "Activities" 
            "Locations" 
            "Records" 
            "Settings" 
            "Sports" 
            "Totals" 
            "Weight"
        )
    
    #https://stackoverflow.com/questions/9952000/using-rsync-include-and-exclude-options-to-include-directory-and-file-by-pattern
    #https://github.com/JonnyTischbein/rsync-server/blob/master/sync-folder.sh
    #Glob should be used inside array (according shellcheck)
    #See https://www.shellcheck.net/wiki/SC2125
    
    for val in "${copyArray[@]}"
        do
            copyStr+=( --include="$val"/*** )
        done
    
    #LOG_NAME="_garmin"
    rsync --dry-run --no-perms --checksum --progress -v -r "${copyStr[@]}" \
         --exclude=* "${inputDir}" "${backupDir}" 
    
    RET_CODE=$?
    
    if test $RET_CODE -eq 0; then
        #writeLog "$LOG_NAME" "${backupDir}"
        notify-send "Garmin 830 Backup is Done"
    fi     
}

garmin

我发现了一条导致这个问题的线。这是

mpointGarmin="$(df -h | grep -i "Garmin" | awk '{print $NF}')"

当我删除这个管道和子shell和硬代码挂载点它的工作。
据我所知,systemd不喜欢subshell调用管道?还是我错了?我该怎么补救?

mjqavswn

mjqavswn1#

从技术上讲,当管道的“读取器”(右侧)已经退出,但“写入器”(左侧)仍在尝试写入更多数据时,“中断管道”是一种正常的情况。
通常在这种情况下,内核会在编写器收到“Broken pipe”错误代码之前使用SIGPIPE * 自动杀死编写器。然而,systemd默认设置信号处理程序为 * 忽略 * SIGPIPE,以避免潜在的(模糊的)安全问题(服务被欺骗写入封闭管道)。
当shell脚本作为服务运行时,指定[Service] IgnoreSIGPIPE=no以将SIGPIPE行为返回为默认值(即使其立即终止进程)。

相关问题