简体   繁体   English

如何将bash别名导入fish

[英]How to import bash aliases into fish

I am missing my bash aliases in fish, and don't want to manually convert all of them to fish functions.我在fish中缺少我的bash别名,并且不想手动将它们全部转换为fish函数。 How to get them all from bash to fish?如何让它们从 bash 到fish?

Bonus points if:奖励积分,如果:

  • the solution supports an iterative process, as in: i can easily change the aliases in bash, and re-convert/re-import them into fish该解决方案支持迭代过程,例如:我可以轻松更改 bash 中的别名,并将它们重新转换/重新导入到 fish
  • the solution also imports bash functions该解决方案还导入了 bash 函数

Convert bash aliases to bash scripts将 bash 别名转换为 bash 脚本

I decided to do this instead of approach below, and putting the scripts into ~/bin/ , which is in my PATH .我决定这样做而不是下面的方法,并将脚本放入~/bin/ ,它在我的PATH This allows me to use them from whatever shell i am currently executing, and it prevents potential problems with quoting.这允许我从我当前正在执行的任何 shell 中使用它们,并且它可以防止引用的潜在问题。

use like so:像这样使用:

# converts all bash aliases to script files
convert_bash_aliases_to_scripts

# removes all scripts previously converted by this script
convert_bash_aliases_to_scripts clean

bash conversion script: bash 转换脚本:

#!/bin/bash
# Convert bash aliases to bash scripts.
#
# Copyright 2018 <hoijui.quaero@gmail.com>, licensed under the GPL-3.0+
#
# Usage:
#   convert_bash_aliases_to_scripts          # converts all bash aliases to script files
#   convert_bash_aliases_to_scripts clean    # removes all scripts previously converted by this script

COLOR_RED=$'\e[0;31m'
COLOR_ORANGE=$'\e[0;33m'
COLOR_BLUE=$'\e[0;34m'
COLOR_BLUE_LIGHT=$'\e[1;34m'
COLOR_GREEN=$'\e[0;32m'
COLOR_BROWN=$'\e[0;33m'
COLOR_YELLOW=$'\e[1;33m'
COLOR_WHITE=$'\e[1;37m'
COLOR_CYAN=$'\e[0;36m'
COLOR_PURPLE=$'\e[0;35m'
COLOR_GRAY=$'\e[1;30m'
COLOR_GRAY_LIGHT=$'\e[0;37m'
COLOR_NONE=$'\e[m' # No Color

OUTPUT_DIR=~/bin/converted/aliases
LINKS_DIR=~/bin
README_FILE_NAME="README.md"
README_FILE="$OUTPUT_DIR/$README_FILE_NAME"

if [ "$1" = "clean" ]
then
    for script_file in $(find "$LINKS_DIR" -maxdepth 1 -type l)
    do
        conv_script_file="$OUTPUT_DIR/$(basename $script_file)"
        if [ -e $conv_script_file ] && [ "$(readlink --canonicalize $script_file)" = "$(realpath $conv_script_file)" ]
        then
            script_name=$(basename $script_file)
            echo "removing converted bash alias-script: $script_name"
            rm $conv_script_file \
                && rm $script_file
        fi
    done
    rm $README_FILE 2> /dev/null
    rmdir $OUTPUT_DIR 2> /dev/null
    exit 0
fi

SOURCE_FILES="${HOME}/.bashrc ${HOME}/.bash_aliases"
mkdir -p $OUTPUT_DIR
echo -e "# Bash alias conversion scripts\n\nsee $0\n\nWARNING: Do NOT manually edit files in this directory. instead, copy them to $LINKS_DIR (replacing the symbolic link that already exists there), and edit that new file.\nIf you edit the files in this dir, it will be replaced on the next (re)conversion from aliases." \
    > $README_FILE
AUTO_IMPORT_WARNING="# WARNING Do NOT edit this file by hand, as it was auto-generated from a bash alias, and may be overwritten in the future. please read ${README_FILE}"

function _is_link_to {
    local file_link=$1
    local file_target=$2
    test -e $file_target \
        && test "$(readlink --canonicalize $file_link)" = "$(realpath $file_target)"
    return $?
}

for source_file in $SOURCE_FILES
do
    IFS=$'\n'
    for a in $(cat $source_file | grep "^alias")
    do
        a_name="$(echo "$a" | sed -e 's/alias \([^=]*\)=.*/\1/')"
        a_command="$(echo "$a" | sed -e 's/alias \([^=]*\)=//' -e 's/[ \t]*#.*$//')"
        if echo "${a_command:0:1}" | grep -q -e "[\'\"]"
        then
            # unquote
            a_command_start=1
            let a_command_end="${#a_command} - 2"
        else
            # leave as is
            a_command_start=0
            let a_command_end="${#a_command}"
        fi
        script_file="$LINKS_DIR/$a_name"
        conv_script_file="$OUTPUT_DIR/$a_name"
        # Check whether the script already exists.
        # If so, we skip importing it, unless it is just a link to a previously imported script.
        log_action="none"
        log_action_color="${COLOR_NONE}"
        log_content=""
        if [ -e $script_file ] && ! $(_is_link_to $script_file $conv_script_file)
        then
            log_action="skipped (exists)"
            log_action_color="${COLOR_ORANGE}"
            log_content=""
        else
            if [ -e $script_file ]
            then
                log_action="reimporting"
                log_action_color="${COLOR_BLUE}"
            else
                log_action="importing"
                log_action_color="${COLOR_GREN}"
            fi

            # write the script file to a temporary location
            conv_script_file_tmp="${conv_script_file}_BAK"
            echo "#!/bin/bash" > $conv_script_file_tmp
            echo -e "$AUTO_IMPORT_WARNING" >> $conv_script_file_tmp
            echo -e "#\n# Imported bash alias '$a_name' from file '$source_file'" >> $conv_script_file_tmp
            cat >> "${conv_script_file_tmp}" <<EOF

${a_command:${a_command_start}:${a_command_end}} \${@}

EOF

            if diff -N ${conv_script_file_tmp} ${conv_script_file} > /dev/null
            then
                log_content="no change"
                log_content_color="${COLOR_NONE}"
            else
                log_content="changed"
                log_content_color="${COLOR_GREEN}"
            fi
            log_content=$(printf "%s %10s -> %s${COLOR_NONE}" "${log_content_color}" "${log_content}" "$a_command")

            mv "${conv_script_file_tmp}" "${conv_script_file}"

            # make the script executable
            chmod +x $conv_script_file
            # remove the link if it already exists (in case of reimport)
            rm $script_file 2> /dev/null
            # .. and re-create it as local symbolic link
            # to the function in the imports dir
            ln --symbolic --relative $conv_script_file $script_file
        fi
        printf "%s%20s: %-25s${COLOR_NONE}%s\n" "${log_action_color}" "${log_action}" "$a_name" "${log_content}"
    done
done

Deprecated: Creating fish wrappers that execute bash code不推荐使用:创建执行 bash 代码的鱼包装器

Below is a script that creates fish script wrappers for the local bash aliases: For each bash alias, it takes the contents, and creates a fish alias/script that executes the code in bash sub-shell.下面是一个为本地 bash 别名创建 fish 脚本包装器的脚本:对于每个 bash 别名,它获取内容,并创建一个 fish 别名/脚本来执行 bash 子 shell 中的代码。 It is not optimal, but is sufficient for most of my aliases.它不是最佳的,但对于我的大多数别名来说已经足够了。

WARNING It might happen that the imported function acts differently then in bash.警告导入的函数可能与 bash 中的行为不同。 You may loose data or accidentally DDOS your coworkers when using them.使用它们时,您可能会丢失数据或意外 DDOS 您的同事。

use like so:像这样使用:

# imports (or reimports) all bash aliases into fish functions, permanently
import_bash_aliases

# removes all fish functions previously imported by this script
import_bash_aliases clean

save this in ~/.config/fish/functions/import_bash_aliases.fish :将其保存在~/.config/fish/functions/import_bash_aliases.fish

#!/usr/bin/fish
# Fish function to import bash aliases
#
# Copyright 2018 <hoijui.quaero@gmail.com>, licensed under the GPL-3.0+
#
# This script is based on a script from Malte Biermann,
# see: https://glot.io/snippets/efh1c4aec0
#
# WARNING: There is no guarantee that the imported aliases work the same way
#   as they do in bash, so be cautious!
#
# Usage:
#   import_bash_aliases          # imports (or reimports) all bash aliases into fish functions, permanently
#   import_bash_aliases clean    # removes all fish functions previously imported by this script from bash aliases

function import_bash_aliases --description 'Converts bash aliases to .fish functions.\nThis might be called repeatedly, and will not override functions that are already defined in fish, except they are merely an older import from this script.'

    set -l FISH_FUNCTIONS_DIR ~/.config/fish/functions
    set -l BASH_IMPORTS_DIR_NAME bash-imports
    set -l BASH_IMPORTS_DIR $FISH_FUNCTIONS_DIR/$BASH_IMPORTS_DIR_NAME
    set -l README_FILE $BASH_IMPORTS_DIR/README.md

    if test "$argv[1]" = "clean"
        for fun_file in (find $FISH_FUNCTIONS_DIR -maxdepth 1 -name '*.fish')
            set -l imp_fun_file $BASH_IMPORTS_DIR/(basename $fun_file)
            if test -e $imp_fun_file ; and test (readlink --canonicalize $fun_file) = (realpath $imp_fun_file)
                set -l fun_name (basename $fun_file '.fish')
                echo "removing imported bash alias/function $fun_name"
                rm $imp_fun_file
                and rm $fun_file
                and functions --erase $fun_name
            end
        end
        rm $README_FILE ^ /dev/null
        rmdir $BASH_IMPORTS_DIR ^ /dev/null
        return 0
    end

    set -l SOURCE_FILES ~/.bashrc ~/.bash_aliases
    mkdir -p $BASH_IMPORTS_DIR
    echo -e "# Bash alias imports\n\nsee `$argv[0]`\n\nWARNING: Do NOT manually edit files in this directory. instead, copy them to $FISH_FUNCTIONS_DIR (replacing the symbolic link that already exists there), and edit that new file.\nIf you edit the files in this dir, it will be replaced on the next (re)import from bash aliases." \
        > $README_FILE
    set -l UNUSED_STUB_MSG "The bash alias corresponding to this function was NOT imported, because a corresponding function already exists at %s\n"
    set -l AUTO_IMPORT_WARNING "# WARNING Do NOT edit this file by hand, as it was auto-generated from a bash alias, and may be overwritten in the future. please read {$README_FILE}"

    function _fish_func_exists
        set -l fun_name $argv[1]
        # This also detects in-memory functions
        functions --query $fun_name
        # This also detects script files in the functions dir
        # that do not contain a function wiht the same name
        or test -e "$FISH_FUNCTIONS_DIR/$fun_name.fish"
        return $status
    end
    function _is_link_to
        set -l file_link $argv[1]
        set -l file_target $argv[2]
        test -e $file_target
        and test (readlink --canonicalize $file_link) = (realpath $file_target)
        return $status
    end

    for source_file in $SOURCE_FILES
        for a in (cat $source_file | grep "^alias")
            set -l a_name (echo $a | sed -e 's/alias \([^=]*\)=.*/\1/')
            set -l a_command (echo $a | sed -e 's/alias \([^=]*\)=//' -e 's/[ \t]*#[^\'\"]\+$//')
            set -l fun_file "$FISH_FUNCTIONS_DIR/$a_name.fish"
            set -l imp_fun_file "$BASH_IMPORTS_DIR/$a_name.fish"
            # Check whether the function already exists.
            # If so, we skip importing it, unless it is just a link to a previously imported function.
            if _fish_func_exists $a_name; and not _is_link_to $fun_file $imp_fun_file
                set_color red
                printf "%20s: %-25s\n" "skipping (exists)" $a_name
                set_color normal
                #printf $UNUSED_STUB_MSG $fun_file > $imp_fun_file
            else
                set_color green
                printf "%20s: %-25s -> %s\n" "(re-)importing" $a_name $a_command
                set_color normal
                # remove the link, in case of re-importing
                rm $fun_file ^ /dev/null

                # write the function file
                echo "#!/usr/bin/fish" > $imp_fun_file
                echo "\
$AUTO_IMPORT_WARNING

function $a_name -d 'bash alias "$a_name" import'
    bash -c $a_command' '\$argv''
end
" \
                    >> $imp_fun_file

                # make the script executable
                chmod +x $imp_fun_file
                # .. and re-create it as local symbolic link
                # to the function in the imports dir
                ln --symbolic --relative $imp_fun_file $fun_file
            end
        end
    end
    # (re-)load all the functions we just defined
    exec fish
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM