Bash shell别名未按预期工作

时间:2014-01-31 21:48:02

标签: bash shell

我正在尝试编写一个使用LibreOffice将.odt文档转换为.pdf的shell脚本,但却遇到别名问题。我的~/.bash_profile中有以下行:

alias soffice='/Applications/LibreOffice.app/Contents/MacOS/soffice'

我的shell脚本中有以下行:

soffice --headless --convert-to pdf $filename

创建“第14行:soffice:command not found”错误。我不确定是怎么回事,因为我可以打电话给

$ alias
alias soffice='/Applications/LibreOffice.app/Contents/MacOS/soffice'

$ soffice --headless --convert-to pdf thefile.odt

也可以。有谁知道为什么别名在我的脚本中不起作用以及我能做些什么呢?感谢。

6 个答案:

答案 0 :(得分:5)

默认情况下,bash别名仅在交互式shell中展开,而不是在脚本中展开。

通常,这是一件好事,因为大多数脚本是在假设他们使用的是真正的命令而不是别名的脚本的情况下编写的。例如,很多人将rm别名为rm -i,将mv设为mv -i。对于交互式工作,这很好:它会让你知道你输错了什么,并试图删除错误的文件。对于可能正在移动许多文件的shell脚本,它很快就会变得尴尬。此外,如果shell脚本重定向了stdin,则会发生意外情况。

因此,最好避免在shell脚本中使用别名。

如果您希望脚本可用soffice快捷方式而不启用别名,请创建名为soffice的文件,其中包含以下内容:

#!/bin/sh
exec /Applications/LibreOffice.app/Contents/MacOS/soffice "$@"

根据需要添加自定义选项,使其可执行,并将其放在路径上的某个位置。

如果您知道自己不想要任何自定义选项或自定义目录,则可以选择创建符号链接:

ln -s /Applications/LibreOffice.app/Contents/MacOS/soffice /somewhere/on/your/path/soffice

许多人在其路径中添加$HOME/bin并将所有此类符号链接和shell脚本放在那里。

更多方法:这个问题有很多答案:

有关基于PATH的解决方案的更多信息,请参阅@Palec@Bryn 的答案。

有关如何使用与别名不同的功能,请参阅@glenn jackman's answer

如果您仍想使用别名,请按@mklement0@user202988

查看答案

答案 1 :(得分:3)

直接回答

您应该使用PATH环境变量而不是定义别名。

export PATH="/Applications/LibreOffice.app/Contents/MacOS:$PATH"

将此行放在~/.bashrc或类似的初始化脚本中。这样,它就会通过环境传递给从Bash中生成的每个进程。如果你只在那里调用它,你也可以使用当前Bash实例的设置。

一般在PATH

PATH是带有可执行文件的冒号分隔(:)目录列表。当shell执行命令时,它会在这些目录中查找同名的可执行文件。目录按从左到右的顺序进行尝试,使用找到的第一个可执行文件。您可以通过which命令查看使用了哪些可执行文件:

$ which cat
/bin/cat

PATH中有一个目录名称会让您大吃一惊。空字符串。你可以在PATH的任一端看到它作为冒号,或者在中间的某个地方看到::。它与指定.(当前目录)具有相同的效果。默认情况下,它位于Windows的PATH中,但通常不在* nixes中。

良好的配置

通常最好在PATH中包含您的个人可执行文件目录,因为任何新添加的可执行文件都将立即可用,而无需再编写其他别名。在* nixes上,用户通常拥有~/bin用于其私有安装的软件。但是,~通常在命令行上由shell扩展,但不在双引号之间扩展。在PATH它没有特殊意义。使用HOME环境变量,因为它正确扩展:

export PATH="$HOME/bin:$PATH"

始终将新目录放在开头。当放入~/bin时,与系统中已安装的名称之一相同的可执行文件优先。通常需要覆盖该工具的默认版本。

我的设置:

palec@Palec:~$ echo "$PATH"
/home/palec/www/ksp/web/bin:/home/palec/bin:/usr/local/bin:/usr/bin:/bin

这是典型的。 /bin用于最基本的程序,/usr/bin用于仍然非常基本的程序和大多数全局安装的软件,/usr/local/bin用于机器特定的,自编译的和第三方软件。然后我的个人~/bin和我为~/www/ksp/web/bin做出贡献的项目。有关/usr contents的更多信息,请参阅TLDP。

答案 2 :(得分:2)

默认情况下,别名未在脚本中展开。

要更改此设置,请在脚本顶部运行shopt -s expand_aliases

<强>更新

@ user202988的答案正确地暗示脚本不会继承其父shell的别名,因此您有两个选择:

  • source来自一个文件,正如@ user202988建议的那样(最简单的情况是:来自你的shell配置文件) - 虽然方便,但这种批量导入会导致无意的别名扩展。
  • 或者,只需在脚本本身的顶部仅定义所需的别名。

最后,听听@ John1024关于完全避免脚本别名的建议。 :)

答案 3 :(得分:2)

如果你查看bash手册页,你会发现:

  

当shell不是交互式时,不会扩展别名,除非   expand_aliases shell选项是使用shopt设置的(参见描述   在SHELL BUILTIN COMMANDS下的shopt。)

所以放一个

shopt -s expand_aliases

在你的剧本中。

确保在脚本中设置别名文件后获取别名文件。

shopt -s expand_aliases
source ~/.bash_aliases

答案 4 :(得分:1)

使用功能并将其导出。然后一个bash脚本就可以使用它了:

$ myfunction() { echo do something here: "$@"; }
$ export -f myfunction

$ cat foo.sh
#!/bin/bash
myfunction with extra args

$ ./foo.sh
do something here: with extra args

当然,这非常脆弱,因为它依赖于你的环境。将这些特殊函数放在一个单独的文件中,您可以从.bashrc和脚本中source

答案 5 :(得分:1)

其他答案试图在全球范围内解决这个问题,因此我将添加一个答案,解决您当前脚本中的问题(没有别名,通常不应在脚本中使用)。

您问题的最恰当答案可能是将目录添加到PATH,即将其添加到〜/ .bashrc ,如@Palec建议的那样。这会使你的别名变得不必要。如果您只想为此脚本解决此问题,可以在脚本中将其添加到PATH!把它放在脚本的顶部(运行soffice命令之前):

export PATH="$PATH:/Applications/LibreOffice.app/Contents/MacOS/soffice"

实际上你可能不需要 export

另一种选择是将soffice设置为变量,即:

soffice="/Applications/LibreOffice.app/Contents/MacOS"

$soffice --headless --convert-to pdf thefile.odt

......但这只是

的便利
/Applications/LibreOffice.app/Contents/MacOS/soffice --headless --convert-to pdf thefile.odt

对于个人脚本中的一次性命令完全可以。对于更广泛的公众来说,像PATH这样更安全的路线将是首选。