Bash脚本函数溢出到其他脚本中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bash脚本函数溢出到其他脚本中相关的知识,希望对你有一定的参考价值。

早晨,

我正在尝试将多个较小的脚本合并为一个大的bash脚本,其中所有内容都通过函数进行调用。

[大多数功能将正常运行(即script.sh update),但是例如给出script.sh status将开始产生与docker()功能相关的错误。

我已经通过shellcheck纠正了所有错误,并尝试将return添加到每个函数中,但仍在提取不正确的函数。

这里是完整的脚本:

#!/bin/bash

# variables and arguments
main() 
    export XZ_OPT=-e9
    distro=$(awk -F'"' '/^NAME/ print $2' /etc/os-release)
    username=$(grep home /etc/passwd | sed 1q | cut -f1 -d:)
    directory_home="/home/$username"
    directory_script="$( cd "$( dirname "$BASH_SOURCE[0]" )" >/dev/null 2>&1 && pwd )"
    rclone_command="rclone --config=$directory_script/rclone.conf"
    docker_restart=("flexget" "cbreader" "syncthing")
    args "$@"
    
args() 
    action=$1
    case "$action" in
        archive) archive ;;
        borg) borg ;;
        docker) docker ;;
        logger) logger ;;
        magnet) magnet ;;
        payslip) payslip ;;
        permissions) permissions ;;
        rclone) rclone_mount ;;
        sshfs) sshfs_mount ;;
        status) status ;;
        sync) sync ;;
        update) update ;;
        *) echo "$0" && available_options ;;
    esac
    

# functions
function available_options() 
    sed -n '/^\tcase/,/\tesac$/p' "$0" | cut -f1 -d")" | sed '1d;$d' | sort | tr -d "*" | xargs
    return
    
function plural() 
    if (("$1">1))
    then
        echo s
    fi
    return
    
function dir_find() 
    find "$directory_home" -maxdepth 3 -mount -type d -name "$1"
    return
    
function domain_find() 
    file_config_traefik="$(dir_find config)/traefik/traefik.toml"
    awk -F'"' '/domain/ print $2' "$file_config_traefik"
    return
    
function git_config() 
    git config --global user.email "$username@$(domain_find)"
    git config --global user.name "$username"
    git config pack.windowMemory 10m
    git config pack.packSizeLimit 20m
    return
    
function delete_docker_env() 
    if [[ -f "$directory_script/.env" ]]
    then
        echo Deleting existing env file
        rm "$directory_script/.env"
    fi
    return
    
function delete_docker_compose() 
    if [[ -f "$directory_script/docker-compose.yml" ]]
    then
        echo Deleting existing env file
        rm "$directory_script/docker-compose.yml"
    fi
    return
    
function write_docker_env() 
    
    printf "NAME=%s\\n" "$username"
    printf "PASS=%s\\n" "$docker_password"
    printf "DOMAIN=%s\\n" "$(domain_find)"
    printf "PUID=%s\\n" "$(id -u)"
    printf "PGID=%s\\n" "$(id -g)"
    printf "TZ=%s\\n" "$(cat /etc/timezone)"
    printf "HOMEDIR=%s\\n" "$directory_home"
    printf "CONFDIR=%s\\n" "$(dir_find config)"
    printf "DOWNDIR=%s\\n" "$(dir_find downloads)"
    printf "POOLDIR=%s\\n" "$(dir_find media)"
    printf "SAVEDIR=%s\\n" "$(dir_find saves)"
    printf "SYNCDIR=%s\\n" "$(dir_find vault)"
    printf "WORKDIR=%s\\n" "$(dir_find paperwork)"
    printf "RCLONE_REMOTE_MEDIA=%s\\n" "$(rclone_remote media)"
    printf "RCLONE_REMOTE_SAVES=%s\\n" "$(rclone_remote saves)"
    printf "RCLONE_REMOTE_WORK=%s\\n" "$(rclone_remote work)"
     > "$directory_script/.env"
    return
    
function payslip_config_write() 
    
    printf "[retriever]\\n"
    printf "type = SimpleIMAPSSLRetriever\\n"
    printf "server = imap.yandex.com\\n"
    printf  "username = %s\\n" "$payslip_username"
    printf  "port = 993\\n"
    printf "password = %s\\n\\n" "$payslip_password"
    printf "[destination]\\n"
    printf "type = Maildir\\n"
    printf "path = %s/\\n" "$directory_temp"
     > getmailrc
    return
    
function payslip_decrypt() 
    cd "$(dir_find paperwork)" || exit
    for i in *pdf
    do
        fileProtected=0
        qpdf "$i" --check || fileProtected=1
        if [ $fileProtected == 1 ]
        then
            qpdf --password=$payslip_encryption --decrypt "$i" "decrypt-$i" && rm "$i"
        fi
    done
    return
    
function rclone_remote() 
    $rclone_command listremotes | grep "$1"
    return
    
function check_running_as_root() 
    if [ "$EUID" -ne 0 ]
    then
        echo "Please run as root"
        exit 0
    fi
    return
    
function include_credentials() 
    source "$directory_script/credentials.db"
    return
    
function archive() 
    rclone_remote=$(rclone_remote backups)
    working_directory=$(dir_find backups)/archives
    echo "$working_directory"
    if [ -z "$*" ]
    then
        echo Creating archives...
        # build folder array?
        cd "$(mktemp -d)" || exit
        for i in "config" "vault"
        do
            tar -cJf "backup-$i-$(date +%Y-%m-%d-%H%M).tar.xz" --ignore-failed-read "$HOME/$i"
        done
        echo "Sending via rclone..."
        for i in *
        do
            du -h "$i"
            $rclone_command move "$i" "$rclone_remote"/archives/
        done
        echo Cleaning up...
        rm -r "$PWD"
        echo Done!
    else
        echo Creating single archive...
        cd "$(mktemp -d)" || exit
        tar -cJf "backup-$1-$(date +%Y-%m-%d-%H%M).tar.xz" --ignore-failed-read "$directory_home/$1"
        echo "Sending via rclone..."
        for i in *
        do
            du -h "$i" && $rclone_command move "$i" "$rclone_remote"/archives/
        done
        echo Cleaning up...
        rm -r "$PWD"
        echo Done!
    fi
    return
    
function update-arch() 
    if [ -x "$(command -v yay)" ]
    then
        yay -Syu --noconfirm
    else
        pacman -Syu --noconfirm
    fi
    return
    
function update-debian() 
    export DEBIAN_FRONTEND=noninteractive
    apt-get update
    apt-get dist-upgrade -y
    apt-get autoremove --purge -y
    apt-get clean
    if [ -x "$(command -v youtube-dl)" ]
    then
        youtube-dl -U
    fi
    if [ -x "$(command -v rclone)" ]
    then
        curl --silent "https://rclone.org/install.sh" | bash
    fi
    return
    
function update-remaining() 
    if [ -f "$directory_home/.config/retroarch/lrcm/lrcm" ]
    then
        "$directory_home/.config/retroarch/lrcm/lrcm" update
    fi
    find "$(dir_find config)" -maxdepth 2 -name ".git" -type d | sed 's/\/.git//' | xargs -P10 -I git -C  pull
    if [ -x "$(command -v we-get)" ]
    then
        pip3 install --upgrade git+https://github.com/rachmadaniHaryono/we-get
    fi
    if [ -x "$(command -v plowmod)" ]
    then
        su -c "plowmod -u" -s /bin/sh "$username"
        chown -R "$username":"$username" "$directory_home/.config/plowshare"
    fi
    return
    
function borg() 
    # https://opensource.com/article/17/10/backing-your-machines-borg
    working_directory=$(dir_find backups)/borg
    echo "$working_directory"
    return
    
function docker() 
    delete_docker_env
#   delete_docker_compose
    include_credentials
    # update submodules
    git pull --recurse-submodules
    # write compose file
#   
#   printf "nope"
#    > docker-compose.yml
    # write env file
    write_docker_env
    # clean up existing stuff
    echo Cleaning up existing docker files
    for i in volume image system network
    do
        docker "$i" prune -f
    done
    docker system prune -af
    # make network, if not existing
    if ! printf "$(docker network ls)" | grep -q "proxy"
    then
        echo Creating docker network
        docker network create proxy
    fi
    # start containers
    echo Starting docker containers
    docker-compose up -d --remove-orphans
    delete_docker_env
    return
    
function logger() 
    git_config
    git_directory="$(dir_find logger)"
    file_git_log="$git_directory/media.log"
    log_command="git --git-dir=$git_directory/.git --work-tree=$git_directory"
    log_remote=$(rclone_remote media)
    if [ ! -e "$git_directory" ]
    then
        mkdir "$git_directory" # make log directory
    fi
    if [ ! -e "$git_directory/.git" ]
    then
        $log_command init # initialise git repo
    fi
    if [ -e "$file_git_log.xz" ]
    then
        xz -d "$file_git_log.xz" # if xz archive exists, decompress
    fi
    if [ -e "$file_git_log" ]
    then
        rm "$file_git_log"
    fi
    $rclone_command ls "$log_remote" | sort -k2 > "$file_git_log" # create log
    $rclone_command size "$log_remote" >> "$file_git_log" # append size
    $log_command add "$file_git_log" # add log file
    $log_command commit -m "Update: $(date +%Y-%m-%d)" # commit to repo, datestamped
    if [ -e "$file_git_log.xz" ]
    then
        rm "$file_git_log.xz"
    fi
    xz "$file_git_log" # compress log
    $log_command gc --aggressive --prune # compress repo
    return
    
function magnet() 
    if [ ! -f "$(dir_find vault)/*.magnet" ]
    then
        echo No magnet files found
        exit 0
    fi
    mag2tor_script_path="$(dir_find config)/magnet2torrent/Magnet_To_Torrent2.py"
    if [ ! -f "$mag2tor_script_path" ]
    then
        echo script not found, downloading
        git clone "https://github.com/danfolkes/Magnet2Torrent.git" "$(dir_find config)/magnet2torrent"
    fi
    sshfs_mount
    cd "$(dir_find vault)" || exit
    for i in *.magnet
    do
        magnet_source="$(cat "$i")"
        python "$mag2tor_script_path" -m "$magnet_source" -o "$(dir_find downloads)/remote/watch/"
        rm "$i"
    done
    return
    
function payslip() 
    # depends on: getmail4 mpack qpdf
    directory_temp="$(mktemp -d)"
    include_credentials
    cd "$directory_temp" || exit
    mkdir cur,new,tmp
    payslip_config_write
    getmail --getmaildir "$directory_temp"
    cd new || exit
    grep "$payslip_sender" ./* | cut -f1 -d: | uniq | xargs munpack -f
    mv "*.pdf" "$(dir_find paperwork)/"
    payslip_decrypt
    rm -r "$directory_temp"
    return
    
function permissions() 
    check_running_as_root
    chown "$username":"$username" "$directory_script/rclone.conf"
    return
    
function rclone_mount() 
    echo rclone mount checker
    for i in backups media paperwork pictures saves
    do
        mount_point="$directory_home/$i"
        if [[ -f "$mount_point/.mountcheck" ]]
        then
            echo "$i" still mounted
        else
            echo "$i" not mounted
            echo force unmounting
            fusermount -uz "$mount_point"
            echo sleeping
            sleep 5
            echo mounting
            $rclone_command mount "drive-$i": "/home/peter/$i" --vfs-cache-mode minimal --allow-other --allow-non-empty --daemon --log-file "$(dir-find config)/logs/rclone-$i.log" # --allow-other requires user_allow_other in /etc/fuse.conf
            echo restarting docker containers
            for j in "$docker_restart[@]"
            do
                docker restart "$j"
            done
        fi
    done
    return
    

function sshfs_mount() 
    include_credentials
    echo sshfs mount checker
    seedbox_host="$seedbox_username.seedbox.io"
    seedbox_mount="$(dir_find downloads)/remote"
    if [[ -d "$seedbox_mount/files" ]]
    then
        echo "sshfs mount exists"
    else
        echo "sshfs mount missing, mounting"
        printf "%s" "$seedbox_password" | sshfs "$seedbox_username@$seedbox_host":/ "$seedbox_mount" -o password_stdin -o allow_other
    fi
    return
    

function status() 
    status_filename=$(dir_find blog)/status.md
    status_timestamp="$(date +%Y-%m-%d) at $(date +%H:%M)"
    status_uptime=$(( $(cut -f1 -d. </proc/uptime) / 86400 ))
    status_cpuavgs=$(cut -d" " -f1-3 < /proc/loadavg)
    status_users=$(uptime | grep -oP '.3user' | sed 's/\user//g' | xargs)
    status_ram=$(printf "%.0f" "$(free | awk '/Mem/ print $3/$2 * 100.0')")
    status_swap=$(printf "%.0f" "$(free | awk '/Swap/ print $3/$2 * 100.0')")
    status_rootuse=$(df / | awk 'ENDprint $5')
    status_dluse=$(df | awk '/downloads/ print $5')
    status_dockers=$(docker ps -q | wc -l)/$(docker ps -aq | wc -l)
    status_packages=$(dpkg -l | grep ^ii -c)
    status_ifdata=$(vnstat -i eth0 -m --oneline | cut -f11 -d\;)
    
        printf -- "---\\nlayout: page\\ntitle: Server Status\\ndescription: A (hopefully) recently generated server status page\\npermalink: /status/\\n---\\n\\n"
        printf "*Generated on %s*\\n\\n" "$status_timestamp"
        printf "* Uptime: %s" "$status_uptime"
        printf " Day%s\\n" "$(plural "$status_uptime")"
        printf "* CPU Load: %s\\n" "$status_cpuavgs"
        printf "* Users: %s\\n" "$status_users"
        printf "* RAM Usage: %s%%\\n" "$status_ram"
        printf "* Swap Usage: %s%%\\n" "$status_swap"
        printf "* Root Usage: %s\\n" "$status_rootuse"
        printf "* Downloads Usage: %s\\n" "$status_dluse"
        printf "* [Dockers](https://github.com/breadcat/Dockerfiles): %s\\n" "$status_dockers"
        printf "* Packages: %s\\n" "$status_packages"
        printf "* Monthly Data: %s\\n\\n" "$status_ifdata"
        printf "Hardware specifications themselves are covered on the [hardware page](/hardware/#server).\\n"
     > "$status_filename"
    return
    
function sync() 
    source=$(rclone_remote gdrive | sed 1q)
    dest=$(rclone_remote gdrive | sed -n 2p)
    echo Syncing "$source" to "$dest"
    $rclone_command sync "$source" "$dest" --drive-server-side-across-configs --verbose --log-file "$(dir_find config)/logs/rclone-sync-$(date +%Y-%m-%d-%H%M).log"
    return
    
function update() 
    check_running_as_root
    if [[ $distro =~ "Debian" ]]
    then
        update-debian
    elif [[ $distro =~ "Arch" ]]
    then
        update-arch
    else
        echo "Who knows what you're running"
    fi
    update-remaining
    return
    

main "$@"
答案

状态功能中有两组花括号。那可能是你的问题吗?

此外,通常将名为main的功能作为功能部分中的最后一个功能。不知道为什么在顶部的变量部分中有两个函数。那只是样式;它不应更改功能。

以上是关于Bash脚本函数溢出到其他脚本中的主要内容,如果未能解决你的问题,请参考以下文章

拦截 bash 脚本函数/系统调用并将它们包装到自定义函数中

Bash脚本编程

删除功能仍然可用

如何在bash shell脚本中包含文件

将小 bash 脚本添加到 cloudbuild.yaml

如何使用 bash -c 调用 bash 脚本函数 [重复]