├── Makefile ├── bass.fish ├── __bass.py └── README.md /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | install -d ~/.config/fish/functions 3 | install __bass.py ~/.config/fish/functions 4 | install bass.fish ~/.config/fish/functions 5 | 6 | uninstall: 7 | rm -f ~/.config/fish/functions/__bass.py 8 | rm -f ~/.config/fish/functions/bass.fish 9 | -------------------------------------------------------------------------------- /bass.fish: -------------------------------------------------------------------------------- 1 | function bass 2 | if test $argv[1] = '-d' 3 | set __bass_debug 4 | set __bash_args $argv[2..-1] 5 | else 6 | set __bash_args $argv 7 | end 8 | 9 | set -l __script (python ~/.config/fish/functions/__bass.py $__bash_args) 10 | if test $__script = '__error' 11 | echo "Bass encountered an error!" 12 | else 13 | source $__script 14 | if set -q __bass_debug 15 | cat $__script 16 | end 17 | rm -f $__script 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /__bass.py: -------------------------------------------------------------------------------- 1 | """ 2 | To be used with a companion fish function like this: 3 | 4 | function refish 5 | set -l _x (python /tmp/bass.py source ~/.nvm/nvim.sh ';' nvm use iojs); source $_x; and rm -f $_x 6 | end 7 | 8 | """ 9 | 10 | from __future__ import print_function 11 | 12 | import json 13 | import subprocess 14 | import sys 15 | import tempfile 16 | 17 | 18 | BASH = 'bash' 19 | 20 | 21 | def gen_script(): 22 | divider = '-__-__-__bass___-env-output-__bass_-__-__-__-__' 23 | 24 | args = [BASH, '-c', 'env'] 25 | output = subprocess.check_output(args, universal_newlines=True) 26 | old_env = output.splitlines() 27 | 28 | command = '{}; echo "{}"; env'.format(' '.join(sys.argv[1:]), divider) 29 | args = [BASH, '-c', command] 30 | output = subprocess.check_output(args, universal_newlines=True) 31 | stdout, new_env = output.split(divider, 1) 32 | new_env = new_env.lstrip().splitlines() 33 | 34 | new_env = [line for line in new_env if '{' not in line and '}' not in line] 35 | 36 | old_env = dict([line.split('=', 1) for line in old_env]) 37 | new_env = dict([line.split('=', 1) for line in new_env]) 38 | 39 | skips = ['PS1', 'SHLVL', 'XPC_SERVICE_NAME'] 40 | 41 | with tempfile.NamedTemporaryFile('w', delete=False) as f: 42 | for line in stdout.splitlines(): 43 | f.write("printf '%s\\n'\n" % line) 44 | for k, v in new_env.items(): 45 | if k in skips: 46 | continue 47 | v1 = old_env.get(k) 48 | if not v1: 49 | f.write('# adding %s=%s\n' % (k, v)) 50 | elif v1 != v: 51 | f.write('# updating %s=%s -> %s\n' % (k, v1, v)) 52 | # process special variables 53 | if k == 'PWD': 54 | f.write('cd "%s"' % v) 55 | continue 56 | else: 57 | continue 58 | if k == 'PATH': 59 | # use json.dumps to reliably escape quotes and backslashes 60 | value = ' '.join([json.dumps(directory) 61 | for directory in v.split(':')]) 62 | else: 63 | # use json.dumps to reliably escape quotes and backslashes 64 | value = json.dumps(v) 65 | f.write('set -g -x %s %s\n' % (k, value)) 66 | 67 | return f.name 68 | 69 | try: 70 | name = gen_script() 71 | except Exception as e: 72 | sys.stderr.write(str(e) + '\n') 73 | print('__error') 74 | else: 75 | print(name) 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bass 2 | 3 | Bass makes it easy to use utilities written for Bash in 4 | [fish shell](https://github.com/fish-shell/fish-shell/). 5 | 6 | Regular bash scripts can be used in fish shell just as scripts written in any 7 | language with proper shebang or explicitly using the interpreter (i.e. using 8 | `bash script.sh`). However, many utilities, such as virtualenv, modifies the 9 | shell environment and requires to be sourced, and therefore cannot be used 10 | in fish. Sometimes, counterparts (such as the excellent 11 | [virtualfish](http://virtualfish.readthedocs.org/en/latest/)) are 12 | created, but that's often not the case. 13 | 14 | Bass is created to make it possible to use bash uilities in fish shell without 15 | any modification. It works by capturing what environment variables are modified 16 | by the utility of interest, and replay the changes in fish. 17 | 18 | # Installation 19 | 20 | Use the Makefile. 21 | 22 | `make install` will copy two files to `~/.config/fish/functions/`. 23 | 24 | `make uninstall` will remove those two files. 25 | 26 | Relaunch the shell for the change to take effect. 27 | 28 | # Example 29 | 30 | Bass is simple to use. Just prefix your bash utility command with `bass`: 31 | 32 | ``` 33 | > bass export X=3 34 | > echo $X 35 | 3 36 | ``` 37 | 38 | Notice that `export X=3` is bash syntax. Bass "transported" the new bash 39 | environment variable back to fish. 40 | 41 | Bass has a debug option so you can see what happened: 42 | 43 | ``` 44 | > bass -d export X=4 45 | # updating X=3 -> 4 46 | set -g -x X 4 47 | ``` 48 | 49 | Here is a more realistic example, using the excellent 50 | [nvm](https://github.com/creationix/nvm): 51 | 52 | ``` 53 | > bass source ~/.nvm/nvm.sh ';' nvm use iojs 54 | Now using io.js v1.1.0 55 | ``` 56 | 57 | Note that semicolon is quoted to avoid being consumed by fish. 58 | 59 | This example takes advantage of the nvm bash utility to switch to iojs. 60 | After the command, iojs is accessible: 61 | 62 | ``` 63 | > which iojs 64 | /Users/edc/.nvm/versions/io.js/v1.1.0/bin/iojs 65 | ``` 66 | 67 | You can then very easily pack the command as a function and feel more at home: 68 | 69 | ``` 70 | > funced mynvm 71 | mynvm> function mynvm 72 | bass source ~/.nvm/nvm.sh ';' nvm $argv 73 | end 74 | 75 | > mynvm list 76 | -> iojs-v1.1.0 77 | system 78 | > mynvm ls-remote 79 | v0.1.14 80 | v0.1.15 81 | ... 82 | ``` 83 | 84 | # Caveats 85 | 86 | At the moment, Bass does not work with interactive utilities. This is not hard 87 | to fix, but I cannot think of a use case. File a ticket if this is something 88 | you find missing. 89 | --------------------------------------------------------------------------------