fish-shell-cookbook, 从 shell 到plate的技巧和食谱

分享于 

26分钟阅读

GitHub

  繁體 雙語
Tips and recipes for fish, from shell to plate. Comprehensive. Friendly. Indispensable.
  • 源代码名称:fish-shell-cookbook
  • 源代码网址:http://www.github.com/jorgebucaran/fish-shell-cookbook
  • fish-shell-cookbook源代码文档
  • fish-shell-cookbook源代码下载
  • Git URL:
    git://www.github.com/jorgebucaran/fish-shell-cookbook.git
    Git Clone代码到本地:
    git clone http://www.github.com/jorgebucaran/fish-shell-cookbook
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/jorgebucaran/fish-shell-cookbook
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    cookbook

    Slack Room

    本文档是一个使用外壳程序解决特殊编程问题的菜谱。 无论你是在肉骨上还是鱼鱼上,总是有一种独特而美味的方法来制备任何类型的鱼。

    许可 CC BY-NC-SA 4.0

    目录

    简介

    众所周知的shell是 bash。ash。csh。ksh和流行的zsh。 所有这些shell都是 ,因此编写符合POSIX规范的脚本应该在任何它们中都没有修改。 这是学习 POSIX shell的唯一原因。

    fish不是 POSIX shell。 你的bash脚本在没有修改的情况下,不会在fish中运行

    make && make install

    将出现错误:"不支持'&&'. 中的使用,请使用'命令,和命令。"

    这很容易修复。

    make; andmake install

    以下是 fish设计文档的引用:

    鱼应该是用户友好的,但不是以表达性为代价。 在功耗和易用性之间的最大权衡可以通过精心设计来避免。

    设置

    :如何安装 fish

    你可以在官方网站上找到指导,或者按照这里提供的指导操作你的操作系统。

    带 Homebrew的macOS
    brew update && brew install fish
    Debian
    wget http://download.opensuse.org/repositories/shells:fish:release:2/Debian_8.0/Release.key
    apt-key add - < Release.keyecho'deb http://download.opensuse.org/repositories/shells:/fish:/release:/2/Debian_8.0//'>>/etc/apt/sources.list.d/fish.list
    apt-get update
    apt-get install fish
    Ubuntu
    sudo apt-add-repository ppa:fish-shell/release-2
    sudo apt-get update
    sudo apt-get install fish
    CentOS
    cd/etc/yum.repos.d/
    wget http://download.opensuse.org/repositories/shells:fish:release:2/CentOS_7/shells:fish:release:2.repo
    yum install fish
    Fedora
    cd/etc/yum.repos.d/
    wget http://download.opensuse.org/repositories/shells:fish:release:2/Fedora_23/shells:fish:release:2.repo
    yum install fish
    来自源的Arch Linux
    pacman -S fish
    Gentoo
    emerge fish
    sudo apt-get -y install git gettext automake autoconf ncurses-dev build-essential libncurses5-dev
    git clone -q --depth 1 https://github.com/fish-shell/fish-shellcd fish-shell
    autoreconf &&./configure
    make && sudo make install

    如何让鱼成为我的默认 shell?

    安装好fish之后,它就可以成为你的默认登录 shell。

    echo/usr/local/bin/fish | sudo tee-a/etc/shells
    chsh -s/usr/local/bin/fish

    如何找到安装鱼的地方?

    使用 which

    which fish
    /usr/local/bin/fish

    启动

    :如何学习鱼

    学习fish的最好方法是阅读官方的文档教程。

    在哪里请求帮助?

    什么是提示,这些丑陋的字符是什么?

    输入命令,并与 shell 解释器。比如。fish进行交互。 在这里阅读更多关于UNIX提示的信息。

    可能是这样的:

    
    x@mbp ~/C/fish-shell>
    
    
    
    

    tilde ~主目录插件的缩写,例如/Users/x, 等等。

    @ 意味着,我可以看到 x,我的用户已经登录到 mbp,这是我给我的工作站的NAME。

    正斜杠 / 是路径分隔符。 目前,我可以看到当前目录在 ~ 附近,在c/鱼壳内部。 C 是父目录的第一个字母,我的例子中的代码。

    在> =2.3 中,可以自定义缩写路径的长度。
    set fish_prompt_pwd_dir_length NUMBER

    或者

    set fish_prompt_pwd_dir_length 0

    没有缩写。

    
    x@mbp ~/Code/fish-shell
    
    
    
    

    这里使用 GREATER 比符号 > 来指示提示的结尾。

    你不喜欢这些约定? 按照你喜欢的方式创建你自己的提示。

    请参见如何在fish中创建我自己的提示

    如何在fish找到我目前的位置?

    你可以通过read环境变量 $PWD find找到你所在的位置。

    echo$PWD/Users/x/Code/fish-shell

    查找当前目录的另一种方法是通过 pwd 内置。

    pwd/Users/x/Code/fish-shell

    在fish中,$PWDpwd 总是解析符号链接。 这意味着,如果你是一个对另一个目录的符号引用,你总是得到实际目录的路径。

    交互式地,pwd 更易于输入。 对于脚本,$PWD 是一个不太昂贵的函数。

    例子
    set-l cwd (pwd)echo"The current working directory is: $cwd"# Versusecho"The current working directory is: $PWD"

    如何在fish中查找和运行命令?

    运行命令键入命令的NAME 并按回车键。

    ls

    或者,开始键入要查找的命令,然后按tab键。 fish将使用内置寻呼程序,你可以浏览并交互式选择命令。

    fish通过查看 $PATH 环境变量了解哪些命令可用。 这里变量包含路径列表,并且这些路径中的每个二进制文件都可以通过它的名称运行。

    打印你的$PATH 内容。

    printf"%sn"$PATH/usr/local/bin
    /usr/bin
    /bin

    或者列出系统中的每个命令并将它们显示在列中。

    ls$PATH| column

    如果列表被截断,请使用:

    ls$PATH| column | less

    使用 kj 导航列表向下/向上,以及 q 以退出。

    $PATH 变量是在环境初始化过程中在fish进程的开始处创建的。 你可以自己修改,前进或者追加到这里变量,比如,在 ~/.config/fish/config.fish. 中

    类似于以前引入的typebuiltinfunctions,*nix 系统通常包含一个或者多个shell不可知的备选方案,比如。whichaproposwhatis 等等。

    这些命令在功能上是重叠的,但也具有独特的功能。 详细了解系统手册手册。

    如何检查命令是否在fish中成功?

    每个命令都返回一个收费的退出代码以指示它们是否成功或者不成功。 0的退出代码意味着成功。 所有的其他命令使用不同的整数来表示可能发生的不同错误。

    你可以使用特殊的只读变量 $status 检查任何命令的退出代码。

    my_commandecho$status

    什么是鱼?

    这里有一种特殊类型的注释,称为 shebang,用来告诉系统使用脚本的路径运行一个程序。 shebang总是写在脚本的开头。

    使用 fish 运行脚本使用如下所示的内容:

    #!/usr/bin/env fish
    例子
    #!/usr/bin/env fishifstatus--is-interactiveecho"We live in an interactive world!"end

    将它的保存到文件并将它的标记为可以执行。

    chmod +x my_script

    上面的系统允许我们使用它的路径直接运行脚本

    ./my_script

    代替

    fish my_script

    变量

    如何设置fish中的环境变量?

    使用 set 插件内置。

    set foo 42

    set 内置接受以下标志以显式声明变量的作用域:

    • -l--local: 仅对最内层的块可用
    • -g--global: 可以在外部模块和其他功能中使用
    • -U--universal: 在所有fish会话之间共享,并在 shell的重启
    • -x--export: 可以用于当前会话中生成的任何子进程

    如果没有使用范围修饰符,则变量将是当前函数的本地变量,否则它将是全局变量。

    如果已经定义变量,则将使用前一个作用域。

    局部变量

    变量 fooif 块外不可用。

    iftrueset-l foo 42endecho"foo=$foo"# foo=
    全局变量

    变量 foo 将在 if 块之外进行自动切换。

    iftrueset-g foo 42endecho"foo=$foo"# foo=42
    通用变量

    变量 foo 将被保留并可以供将来的shell 会话使用。

    set-U foo 42
    fishecho"foo=$foo"# foo=42
    导出的变量

    变量 foo 将是本地的和导出的,因此可以用于在 if 块中创建的fish 子进程。

    iftrueset-lx foo 42
     fish -c'echo"foo=$foo"'# foo=42end

    变量 foo 将是全局的,但是由于它不是导出的,因这里它不可以用于 fish 子进程。

    set-g foo 42
    fish -c'echo"foo=$foo"'# foo=

    变量 GPG_AGENT_INFO 是通用的和导出的,因此在以后的shell 会话和子进程中保留。

    set-Ux GPG_AGENT_INFO/Users/x/.gnupg/S.gpg-agent:12345:2

    如何导出fish中的变量?

    使用 set 内置和范围修饰符 -x 或者 --export

    set-x foo 42
    fish -c'echo"foo=$foo"'# foo=42

    如何列出fish中的所有 环境变量?

    使用不带任何修饰符标志的set 内置。

    set

    若要只打印变量名而不打印值,请使用 --name

    set--names

    不截断长划线使用 --long

    set--long

    如何在鱼中永久地设定 $PATH

    正确地向 $PATH 添加路径的正确方法是使用 fish $fish_user_paths 变量。

    set-U fish_user_paths $fish_user_paths my_path

    有关更多信息,请参见fish教程中的 $PATH 插件。

    如何从 $PATH 中删除路径?

    使用带有 -e 或者 --erase 标志的set 内置内置框和contains,以查找要删除的路径索引。

    ifset-l index (contains-i$my_path$PATH)
     set-e PATH[$index]end

    如何检查fish中的路径是否存在于fish中?

    使用 contains 插件内置。

    ifcontains$my_path$PATH# $my_path is in $PATHend

    用户定义函数

    :如何在fish中创建函数

    使用 function 插件内置。

    function mkdirp
     mkdir-p$argvend

    要在将来的fish会话中使用这个函数,将它保存到 ~/.config/fish/functions/mkdirp.fish. 中是一个干净的方法,可以使用。

    funcsave mkdirp

    可以使用 functions 内置内置函数将函数定义写到文件中。

    functions mkdirp > ~/.config/fish/functions/mkdirp.fish

    如何在fish中创建 private 函数?

    你不能。在fish中,函数总是 public。

    作为解决方法,使用自定义命名空间将你想要处理的任何函数作为 private。

    function _prefix_my_functionend

    使用 functions -e 插件模拟 private 范围是不可能的,但是它很可能会表现不佳。

    例子
    function foo
     function _foo
     echo Foo
     functions-e _foo # Erase _fooend _fooend

    应将名称和文件名匹配?

    是,延迟加载/自动加载机制依赖这里约定来工作。

    如果文件 ~/.config/fish/functions/foo.fish 具有有效的函数定义 bar:

    • 在新 shell 中,尝试运行 bar 会产生未知的命令错误。
    • 键入 foo 将高亮显示为有效命令,但产生未知的命令错误。
    • 尝试再次运行 bar 可以按预期方式运行。
    • 例子

    bar 保存到 ~/.config/fish/functions/foo.fish.

    function bar
     echo Barendfunctions bar > ~/.config/fish/functions/foo.fish

    创建新的shell 会话。

     
    fish
    
    
    
     

    试着运行 bar,然后是 foo,然后再。

    
    bar
    
    
    # fish: Unknown command 'bar'
    
    
    foo
    
    
    # fish: Unknown command 'foo'
    
    
    bar
    
    
    # Bar
    
    
    
    

    我可以在文件中定义多个函数?

    当然可以注意 fish没有 private 函数,所以文件中的每个函数在加载文件时都在全局作用域中结束。 同时,每个函数也被暂时加载,它不像每个文件使用一个函数那样有效。

    如何在fish中显示函数的定义。

    如果你知道命令是一个函数,那么使用 functions 内置。

    functions my_function

    如果不确定命令是函数,内置命令还是系统命令,请使用 type 命令。

    type fish
    fish is/usr/local/bin/fish

    :鱼的功能。构建和命令之间的区别是什么

    系统命令是可执行脚本。二进制文件或者指向 $PATH 变量中存在的二进制文件的符号链接。 命令作为子进程运行,并且只能访问已经导出的环境变量。 示例:fish

    函数被定义。一些函数包含在你的fish分布中。 示例:eval

    内置是用fish可执行文件编译的命令。 内置可以访问环境,因此它们的行为类似于函数。 生成不生成子进程。 示例:functions

    如何列出fish定义的函数?

    使用不带参数的 functions 插件。

    列表将省略 NAME 以下划线开头的函数。 以下划线开头的函数通常称为隐藏。 要显示所有内容,请使用 functions -a 或者 functions --all

    或者,启动基于web的配置并导航到/functions 选项卡。

    
    fish_config functions
    
    
    
    

    如何检查fish中函数是否存在?

    使用 type 用户定义函数查询有关命令。内置或者函数的信息。

    ifnottype--quiet"$command_name"exit 1end
    用户 builtin --names 查询生成。
    ifnotcontains -- "$command_name" (builtin--names)
     exit 1end
    用户 functions --query 检查函数是否存在。
    ifnotfunctions--query"$command_name"exit 1end
    用户 command --search 对于其他命令。
    ifnotcommand--search"$command_name">/dev/null
     exit 1end

    fish> = 2.5更容易

    ifnotcommand--search--quiet"$command_name"exit 1end

    命令行参数

    如何访问传递给fish函数的参数?

    使用 $argv 变量。

    function Foo
     printf"%sn"$argvendFoo foo bar baz
    foo
    bar
    baz

    如何访问fish中传递给脚本的参数?

    使用 $argv 变量在运行脚本时传递参数。

    fish./my_script foo bar baz
    foo
    bar
    baz
    示例:my_script
    #!/usr/bin/env fishprintf"%sn"$argv

    如何解析fish中的命令行 参数?

    使用 for 循环。

    for option in$argvswitch"$option"case-f--foocase-b--barcase*printf"error: Unknown option %sn"$optionendend

    有关更完整的CLI解析解决方案,请参见 getopts

    别名

    如何定义fish中的别名?

    创建一个 function 文件并将它的保存到

    function rimraf
     rm-rf$argvend

    为了向后兼容 POSIX shell,可以使用 alias 函数。

    alias rimraf "rm -rf"

    避免在中使用 alias,请参见下一节中的

    别名有什么问题?

    使用 alias 创建的别名在新的shell 会话中不可用。 如果这是你需要的行为,那么 alias 可以接受交互式使用。

    在整个 shell 会话中保持别名,创建一个 function 并将它的保存到 ~/.config/fish/functions.,这利用了fish函数延迟加载/自动加载机制。

    在 ~/.config/fish/config.fish 中使用 alias 会减慢 shell 开始,因为每个别名都会被暂时加载。

    配置

    fish中的。bash_profile或者。bashrc等价?

    你的fish配置保存到 ~/.config/fish/config.fish.

    IO

    如何从文件中读取文件?

    要逐行读取文件行,请使用 read 内置。

    whileread-la line
     echo$lineend< my_file

    如何从fish中读取数据?

    使用 read 插件内置。

    read--prompt"echo 'Name: ' "-l name
     
    Name: Marvin
    
    
    
     
    echo$nameMarvin

    要从任意输入流读取 read,请使用和 while 内置。

    whileread-la line
     echo$lineend

    如何将stdout或者stderr重定向到fish的文件?

    将stderr重定向到 $my_file

    my_command ^$my_file

    或者

    my_command 2>$my_file

    将stdout重定向到 $my_file

    my_command >$my_file

    将stdout重定向到 stderr。

    my_command >&2

    将stderr重定向到 stdout。

    my_command 2>&1

    并发

    如何在fish中运行命令?

    使用 &

    sleep 10 &

    请参阅fish文档中的后台作业插件。

    如何检查是否有后台作业运行?

    使用 jobs 插件内置。

    ifjobs>/dev/null
     echo Busyend

    如何在fish中同步两个或者更多后台任务?

    fish没有 wait 命令,但是你可以编写自己的。

    首先检查后台是否运行任务,解析来自 jobs 插件的输出。

    按作业ID分析
    function get_jobs
     jobs$argv|commandawk-v FS=t'/[0-9]+t/{ jobs[++nJobs] = $1 } END { for (i in jobs) { print(jobs[i]) } exit nJobs == 0 }'end
    按组ID分析
    function get_jobs
     jobs-g|commandawk'NR> 0 { print; i++ } END { exit i == 0 }'end

    然后,阻止前台,直到所有后台作业完成。

    functionwaitwhiletrueset-l has_jobs
     set-l all_jobs (get_jobs)
     orbreakfor j in$argvifcontains -- $j$all_jobsset-e has_jobs
     breakendendifset-q has_jobs
     breakendendend
    例子
    set-l urls "https://"{google,twitter,youtube,facebook,github}".com"for url in$urls fish -c"curl -Lw "$url: %{time_total}sn" -o/dev/null -s $url"&endwait (get_jobs)

    :如何等待fish中的后台进程

    fish没有 wait 内置内置。 要等待后台进程完成,请使用中描述的解决方案如何同步fish中的两个或者多个后台任务? 。


    Shell  Recipe  FISH  
    相关文章