以.test而非./test的身份执行


26

假设我与可执行文件位于同一文件夹中,则需要输入以下内容才能执行该文件:

./file

我宁愿不必键入/,因为/我很难键入。

有没有更简单的方法来执行文件?理想情况下,只是一些简单的语法,例如:

.file

或其他方式,但比必须在/该处插入字符要容易。

也许有某种方法可以在/bin目录中放置某些内容,或为解释器创建别名,以便可以使用:

p file

9
也许使用xmodmap交换/与另一个密钥?因此,至少键入起来更容易
Guy

26
另外,在Unix中广泛/使用,主要用作目录分隔符。您最好找到一种更简单的输入方式。
克莱里斯

7
自以来,@ RossPresser这个问题变得毫无意义。由于任何新手都应该知道的技术原因,文件开头的。和。是两个完全不同的含义。/对于绝大多数人来说,键入它并不难,并且如果OP受到伤害而无法避免这种情况,那么他们应该考虑使用其他键盘布局,因为/在终端中无法完全避免这种情况。
JFA

1
@JFA欧洲大陆和南美使用的大多数键盘布局都使用了/shift-7,即使没有受伤也很难打字。
nitro2k01

6
编辑历史:“ 为什么不能网络接口简单地指导,使通过远程主机的所有网络查询,通过SSH端口22上 ”ಠ_ಠ
德里克朕会功夫

Answers:


35

它可以是“危险的”,但您可以拥有。在您的路径中。

正如其他人所说,这可能很危险,因此请务必确保。在PATH的末尾而不是开始。


1
真的看不到这是什么“危险”:我的道路早在linux之前就一直是这样,它从未引起丝毫问题。
jamesqf

21
@jamesqf是有风险的,因为如果您cd访问的是世界可写目录,并且尝试使用不在您的路径中的命令,则您可能会执行(可能是恶意的)可执行文件,其名称与某人在该路径中写入的名称相同。如果放在.路径的开始,那就更糟了。在这种情况下,ls如果您尝试ls在该目录中调用,将执行一个名为的恶意可执行文件。
字节化

2
由于上述原因,请避免这种情况。该p命令会更好。
Guido

11
@jamesqf当它是“您的”系统时,只有您使用它,它还不错。问题出在多用户系统上(多年来使许多Unix管理员绊倒了)。从.早期开始PATH,恶意用户需要做的就是ls在目录中放置一个伪造命令,并说服管理员“看一些奇怪的东西”,并且他们具有root访问权限。
TripeHound '17

1
好的解决方案,尽管如果文件碰巧被命名为test,则不能解决问题,就像在问题的标题中一样(因为test它是内置的shell,并且可能$PATH已经存在于您的某个位置)。
yellowantphil '17

71

../至少在现代的Bash shell中会自动完成(键入.并按Tab),因此您不必使用复杂或不安全的(如PATH修改)解决方案。

如果它不能自动完成,则可能需要安装“ bash-completion”软件包。


你确定吗?.有多个完成候选对象:(.当前目录),..(父目录),.命令(bash为该目录提供了非标准的别名source)以及存在的任何点文件。也许bash-completion程序包忽略了这个;我觉得这很烦人(例如,它使得不可能在make命令行中用制表符完成dir名称,并且通常对于充满隐式规则的makefile太糟糕了),所以我总是将其清除。
R.,

3
我尝试过,是的,它确实以这种方式自动完成。在几乎每种情况下,普通用户都希望这样做:我认为我从未见过应该可执行的dotfile,在子目录中运行某些东西比在父目录中运行东西要普遍得多,而IMO确实如此找make目标真该死。
l0b0

使用bash 3.2不会自动完成。这是bash 4中的新功能吗?
Calimo

2
@Calimo在最新版本的bash-completion中更可能是新的。这远非根本改变。
l0b0

42

或者..也许在bashrc文件中给解释器起别名,然后简单地

   p  file

可以编写这样的函数:

p() {
 ./"$@"
}

在你的~/.bashrc。然后,您将可以p app arguments代替运行./app arguments。该解决方案适用于任何类型的可执行文件,包括脚本和二进制文件。

"$@"扩展为传递给函数的参数的引号列表(保留glob或变量扩展中的所有特殊字符),并且,正如@Scott指出的那样,bash它足够聪明./,可以保留在它们的第一个中,保留其余部分。


虽然在另一个命令下运行应用程序不太普遍,但是喜欢strace -f p app查看系统调用或$(which time) p app查看所需时间。 p因为在我设计的这两个特定示例中,可执行脚本会更好地工作。这两种解决方案都无法使用ldd p app,尽管可能需要这样的路径ldd 有所不同,也许是出于这样的原因。
sourcejedi '17

是的,替换p app args./app args的方式是不可见的任何人都将需要通过某种预处理的管道外壳输入和替代时在意外的地方:)出现会导致各种有趣的
aitap

1
在这种情况下,周围不应该没有引号$@吗?否则,它将仅将一个大参数传递给程序。
Kroltan'2

7
@Kroltan号$@是一个数组。在中扩展时",每个参数都扩展为一个单独的单词。$*表现出您的思维方式。
8bittree

3
我相信您已经使这一过程变得不必要了,这p() { ./"$@"; }就是您所需要的。
斯科特,

11

你可以把.你的$PATH加入如PATH=$PATH:./etc/profile,这样你就可以执行file只是写file,除非是在你的路径(例如一些其他的文件夹/usr/bin/)。请注意,这通常不是一个好主意。

不好的原因:假设您不完全信任目录的内容-您已经从某个地方下载了目录,并且想在运行它之前进行研究,或者您是系统管理员正在帮助您用户,方法是查看用户的主目录等。您想列出目录,因此尝试键入ls,但是哎呀,您输入了错字,最后却键入了sl。这个恶意目录的作者预料到了这一点,并在其中放置了一个名为“ sl”的shell脚本,该脚本运行“ rm -rf --no-preserve-root /”(或更恶意的东西,例如安装一个rootkit)。

(感谢@Muzer的解释)


13
尽管我完全同意,但是这可能很能解释为什么这不是一个好主意。
ymbirtt '02

16
不好的原因:假设您不完全信任目录的内容-您已经从某个地方下载了目录,并且想在运行它之前进行研究,或者您是系统管理员正在帮助您用户,方法是查看用户的主目录等。您想列出目录,因此尝试键入ls,但是哎呀,您输入了错字,最后却键入了sl。这个恶意目录的作者预料到了这一点,并在其中放置了一个名为“ sl”的shell脚本,该脚本运行“ rm -rf --no-preserve-root /”(或更恶意的东西,例如安装一个rootkit)。
Muzer

2
值得说明的是,如果当前目录是在$ PATH的开始,相反,攻击者可以只覆盖LS或其他常用命令
DélissonJUNIO

@Muzer Huuuge锡箔帽子在这里。
草帽鸡

4
@GillBates作为系统管理员,您必须要警惕,因为它必须处理实际的和潜在的恶意用户,或者是要分析可疑档案的人。如果这些都不适用,那么我同意你的看法。不过,我仍然不认为这是一个好习惯,因为您永远不知道自己的情况会在什么时候改变,就只能得到其中的一份工作,并且会因训练自己依靠不安全的行为而无休止地骂自己; )
Muzer's

10

例如,您可以致电口译员

bash test

在这种情况下,即使脚本没有shebang行(例如#!/bin/bash)或可执行位,它也将运行。您还必须知道正确的解释器才能运行它。您可以先阅读文件的shebang行,以确保您调用了正确的解释器,例如shebang行显示

#!/usr/bin/env python3

你会打电话

python3 test

7
解释器仅解释代码,它们将不运行二进制文件
Mc Kernel

这个答案有些合乎逻辑,因为也许可以在bashrc文件中为解释器提供别名。

5
@McKernel好点,它只有在有解释器的情况下才有效,不适用于编译的可执行文件
Zanna

2
有针对编译后的可执行文件的解释器:/lib/ld.so
Dmitry Kudriavtsev

7

据我所知,除非在env路径中包含文件,否则无法实现它,因此只需键入即可运行它: file

.file无法使用,因为那是另一个文件名。这是一个名为.file而不是的文件./file

我觉得斜线可能很难为您输入,因为可能是非英文版式?在这种情况下,这也发生在我身上,因此我经常通过在Windows中按Alt + Shift来交换键盘布局为英文(我从ssh使用Linux)


7

人们建议增加.PATH,这是危险的,因为它创建了一个风险,你会意外地运行种植在世界可写目录中的恶意程序。但是,如果你有几个目录,你自己可执行程序和只能通过你写的,那么它的安全(相当安全的?)把这些导演(IES)进入PATH,加入这样一行

PATH=$PATH:~/dev/myprog1:~/dev/myprog2

到您的~/.bashrc文件。当然,这意味着您可以从文件系统中任何位置的那些目录之一运行程序。例如,您可以cd /etc输入foo,它将运行~/dev/myprog1/foo。这有一个小缺点,即您不能在多个目录中包含多个目录中的同名程序。具体来说,如果您foo 同时在~/dev/myprog1和中都调用了程序,则只能~/dev/myprog2通过指定路径来运行第二个程序。同样,如果您有~/dev/myprog1/cat-但为什么要这么做?


如果只有几个程序可以使用,则另一种方法是为其定义别名:

alias gizmo='./gizmo'
alias gonzo='./gonzo'

或者,您可以称呼别名.gizmo.gonzo 如果您觉得更直观。

实际上,在某种程度上,这与.放入您的服务器具有相同的安全风险PATH。如果恶意用户可以读取你的.bashrc,看看你的别名,那么他可能把恶意软件称为gizmogonzo随机目录中的希望,你会运行它。最好使它们使用绝对路径名:

alias gizmo='~/dev/myprog1/gizmo'
alias gonzo='~/dev/myprog2/gonzo'

顺便说一句,您应该避免命名可执行文件test,因为这是Shell内置命令,并且只能通过指定路径或其他技巧来使用该名称运行程序。


或者,您可以制作配方(如果使用的是Makefiles),然后执行do make gizmomake gonzo
ihato

很抱歉,但是我不确定我是否理解与问题或答案的关系。您是否建议OP Makefile在每个目录中创建一个,以便make gizmo通过运行 结束操作gizmo?(1)p问题中提出的,最初由aitap实现并由Scott完善的方法似乎与该函数做同样的事情很尴尬。(2)可以这样传递参数吗?make gizmo arg1 arg2相当于的ISTM make gizmo; make arg1; make arg2
G-Man说'恢复莫妮卡'

1
(1)也许我的假设是错误的,但我不清楚OP是否希望避免./每个目录中使用。在我看来,他正在开发某些东西,只需要./file经常运行产生的程序即可。我真的没有想到其他任何情况下,经常需要运行本地文件,并且如果他不经常运行该文件,他就不会打扰问这个问题(他说困难并非不可能)(2)并非如此,而是您可以在配方中传递参数。
ihato

(1)好吧,我想我们可以同意,OP的动机和问题范围尚不清楚。(2)感谢您的链接。
G-Man说'Resstate Monica''02 /

3

为了进一步扩展Zanna关于解释器的答案(对不起,没有评论):动态加载器(ld.so)是本机可执行文件(又名二进制ELF文件)的“解释器” ,但它通常不理解您想要的语法:

$ /usr/lib/ld-linux-x86-64.so.2 program
program: error while loading shared libraries: program: cannot open shared object file
$ /usr/lib/ld-linux-x86-64.so.2 ./program
<program is launched>

(此外,除非您符号链接ld.so到路径中,否则仍然需要编写/s)


这是特定于Linux的,对吗?您能否再解释一下,为什么行得通?我以为(Linux)内核会进行解析并确定是否以及如何运行二进制文件,这就是为什么binfmt_misc
phk

2
@phk该文件特定于Linux,但是动态链接程序/加载程序的概念不是。例如,FreeBSD有其自己的/libexec/ld-elf.so.1。在Linux上,这不像“确定如何运行二进制文件”那样简单:binfmt_misc通过魔术数字(ELF,shebang脚本,CIL)检测文件格式。之后,binfmt_elf将调用处理程序。它解析ELF标头和节;.interp该部分包含动态加载程序的路径;该加载程序由内核启动,进行重定位,然后跳转到_start。在FreeBSD上(不确定其他),没有binfmt,但是原理是+/-类似的。
bacondrop

1
@phk为何起作用- ld.so没有.interp并且是静态链接的,这意味着它不需要另一个动态链接器/加载器来解析其外部符号并进行重定位数学。
bacondrop

ISTR Solaris也具有与此等效的功能。
G-Man说'Resstate Monica''5

3

如果允许我们开始配置东西

mkdir -p ~/.local/bin
cat > ~/.local/bin/x << 'EOF'
#!/bin/sh
N="$1"
shift
exec "./$N" "$@"
EOF
chmod a+x ~/.local/bin/x

大多数现代发行版已经在$ PATH中包含〜/ .local / bin(如果没有,则添加export PATH="$HOME/.local/bin:$PATH"到您的文件~/.profile中)。然后,您可以使用x file来运行./file

不要尝试定义.命令。该命令. scriptscript在当前shell中运行。这允许script为当前外壳定义环境变量。


3
我认为这里可能有一个很好的建议,但是没有任何解释。我可以解决,但是经验不足的用户将没有机会。
IMSoP '17

无需转移$ 1。只是exec "$@"
reinierpost

$ (ln -s /bin/ls my-ls && exec my-ls) # bash: exec: my-ls: not found
sourcejedi

(1)没有必要shift $1;只是exec ./"$@"。(2)由于您正在谈论Shell脚本,因此建议人们不要定义.命令有点无意义/误导,因为无法创建名为的文件.。(定义一个别名或shell函数是可能的,而且非常不明智.。)
Scott

1

如果允许我们创建帮助程序脚本,则可以创建一个将pwd添加到PATH的帮助程序,然后运行

. pathhelper    #adds pwd to path
file            #now it can be run without ./

这样可以避免添加“。” 到该路径,并在某处可能想要在其中运行的每条路径污染您的.profile。

我们可以使该方法更进一步,方法是创建一个辅助程序,该辅助程序将使用经过修改的PATH启动新的Shell。如果使用目录作为参数(默认使用pwd),则其功能类似于pushd编辑路径的a。您可能需要注意,退出子Shell时对其他环境变量的任何更改都将丢失,但是在长时间运行的Shell中,您的PATH变量不会杂乱无章。根据您的工作流程,这可能是有利的。

:outer shell prompt$; subshellpathhelper    # launches a subshell with modified PATH
: subshell prompt $ ; file                  # in the subshell it can be run without ./

但是我想,如果您想运行它,您可能会破解pushdpopd因此他们可以对路径进行相同的修改,而无需创建子shell,否则将丢失其他更改。

pushd --path ~/some/path/    # normal pushd plus adds target to path
file                         # it can be run without ./ until you popd

(您不能这样做,cd因为它没有的类似物popd。)

您还可以创建一对专门的助手来仅推送和弹出PATH条目。最有效的方法实际上取决于您的使用模式。


实际上,您可以在中执行类似的操作cd,但它却更远:创建一个文件(如).dircmds,然后破解cd以使定义的命令./.dircmds在切换前不可用,而在切换后立即可用。
ShadSterling

-1

. script.sh只要您要执行的脚本在当前目录中,就可以使用语法。

您还可以在解释器之前添加前缀,例如sh或bash。例:bash script.sh


8
. script.sh如果脚本包含exit,将会中断,从而产生意想不到的效果,例如,如果脚本“临时”重新定义了PATH;它也仅适用于当前shell的脚本
sourcejedi

@sourcejedi关于exit您可以将其放在括号内,即一个子shell,但请注意,它仍然仅适用于同一shell中的脚本。
phk

问题是“可执行文件”。这些不适用于二进制可执行文件。仅用于脚本。第二段重复了Zanna的回答
斯科特,

好吧,我不好,我主要执行和开发bash东西,所以我以为我们在谈论bash脚本:)
UltimateByte

不仅用于脚本,而且仅用于Bash脚本。
Oskar Skog's
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.