Source csh from bash

From AstroNuWiki
Jump to: navigation, search

Существует возможность использовать файлы csh из среды bash. Идея простая: при выполнении файла командой source необходимые изменения касаются в первую очередь переменных текущей среды. Все остальные изменения (содержимого файлов, разрешений, настроек) не связаны с состоянием текущей оболочки. Значит можно сравнить состояние любой среды до и после применения файла, и сделать необходимые изменения.

Сразу отмечу, для загрузки используется родная оболочка, поэтому для иморта csh в bash, оболочка tcsh всё-равно нужна.

Рассмотрим три оболочки: bash, tcsh и fish

1. Отслеживание изменения переменных среды

Тут всё просто, надо выполнить diff для команды env до и после применения исходника. При этом любые вложенные вызовы source тоже обработаются корректно, как и все остальные команды. Скрипт автоматически определяет тип оболочки по расширению.

#!/bin/sh
function filter (){
    /bin/grep -vE "(^[^\+-]|^\+\+\+|^---|^[\+-]_|^[\+-]PIPESTATUS|^[\+-]COLUMNS)"
}

test "$*" || exit 1

case "$1" in
    *.sh)
        /bin/bash -c "diff -u <(env | sort) <(source $1 1>&2  ; env | sort)" | filter
        ;;
    *.csh|*.tcsh)
        /bin/tcsh -c "env | sort >/tmp/s_s1; source $1 ; env | sort>/tmp/s_s2; diff -u /tmp/s_s1 /tmp/s_s2" | filter
        rm /tmp/s_s[12]>/dev/null
        ;;
    *.fish)
        /usr/bin/fish -c "diff -u (env | sort | psub) (. $1 >&2 ; env | sort | psub)" | filter
        ;;
    *)
        echo Unknown source type $1
        ;;
esac

2. Импорт в текущую оболочку

Импорт происходит уже при помощи команды source текущей оболочке.

bash

В ~/.bashrc добавляем следующие функции:

  • Для замены вывода команды diff. "+ENV=env" на "export ENV env", "-ENV" на "unset ENV"
bashimport () {
    sed "s/^-\([^=]\+\)=.\+\$/unset \1/; s/^+/export /;"
}
ssource () {
    source <(sourceload $1 | bashimport)
}

Использование:

ssource source_me.csh
ssource source_me.fish

tcsh

Насколько я знаю, в tcsh нет функций, поэтому придётся обойтись source-файлом:

alias cshdifffilter 'sed "s/^-\([^=]\+\)=.\+/unsetenv \1/; s/^+/setenv /; s/=/ /g"'
setenv file /tmp/cshimport.csh
sourceload $1 | cshdifffilter > $file
source $file
rm $file

Используются так:

source /path/to/ssource.csh source_me.sh
source /path/to/ssource.csh source_me.fish

В файле ~/.tcshrc можно создать алиасы (но я не проверял):

alias ssource "source /path/to/ssource.csh $1"

fish

В fish нету команды source, т.ч. её можно смело подменить:

function source --description 'Source fish/sh/csh file'
    for file in $argv
        switch $file
            case \*.fish
                . $file
            case \*.sh \*.csh \*.tcsh
                sourceload $file | fishimport
            case \*
                echo Unknown source type $file
        end
    end
end

С импортом немного сложнее. Дело в том, что fish проверяет существование путей, добавляемых в PATH, поэтому надо перестраховаться:

function fishimport --description 'Import env diff'
    set -l pattern "s/^-\([^=]\+\)=.\+\$/set -e \1/; s/^+/set -gx /; s/=/ /g; s/:/ /g"
    set -l patternP "s/^[-+]PATH=//; s/:/ /g"
    while read line
        set -l sub (expr substr "$line" 1 5)
        test "$sub" = "-PATH"; and continue

        if test "$sub" = "+PATH"
            eval set line (echo $line | sed  $patternP)
            for pt in $line
                if not contains $pt $PATH
                    set -gx PATH $PATH $pt ^/dev/null; or echo "Unable to add '$pt' to \$PATH. Check existance."
                end
            end
            continue
        end
        echo $line | sed  $pattern | .
    end
end

Использование:

source source_me.sh
source source_me.csh
source source_me.fish

User:MaximGonchar 11:29, 2 November 2010 (MSK)