如何找出命令是否以POSIX兼容的方式存在? [英] How to find out if a command exists in a POSIX compliant manner?

查看:110
本文介绍了如何找出命令是否以POSIX兼容的方式存在?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请参见 POSIX.1-2004 .

See the discussion at Is `command -v` option required in a POSIX shell? Is posh compliant with POSIX?. It describes that type as well as command -v option is optional in POSIX.1-2004.

检查Bash脚本中是否存在程序的答案标记为正确也无济于事.就像type一样,hash在POSIX.1-2004中也被标记为XSI.参见 http://pubs.opengroup.org/onlinepubs/009695399/utilities/hash .html .

The answer marked correct at Check if a program exists from a Bash script doesn't help either. Just like type, hash is also marked as XSI in POSIX.1-2004. See http://pubs.opengroup.org/onlinepubs/009695399/utilities/hash.html.

那么编写POS脚本来查找系统上是否存在命令的POSIX兼容方式是什么?

Then what would be a POSIX compliant way to write a shell script to find if a command exists on the system or not?

推荐答案

您要如何处理?您可以在$PATH当前值的目录中查找该命令;您可以查看默认情况下为系统PATH指定的目录(getconf PATH,只要 getconf 存在于PATH)上.

How do you want to go about it? You can look for the command on directories in the current value of $PATH; you could look in the directories specified by default for the system PATH (getconf PATH as long as getconf exists on PATH).

您将使用哪种实现语言? (例如:我有一个Perl实现,可以很好地在$PATH上找到可执行文件-但Perl不是POSIX的一部分;它与您远程相关吗?)

Which implementation language are you going to use? (For example: I have a Perl implementation that does a decent job finding executables on $PATH — but Perl is not part of POSIX; is it remotely relevant to you?)

为什么不简单地尝试运行它呢?如果您要处理基于 Busybox 的系统,则无法通过搜索找到很多可执行文件-它们内置在外壳中.主要警告是如果命令在不带参数的情况下运行时是否会执行某些危险操作,但是很少有POSIX命令执行此操作.您可能还需要确定哪些命令退出状态指示未找到该命令,而该命令则反对不使用适当的参数调用该命令.而且几乎不能保证所有系统在此方面都是一致的.如果您没有聚集的话,这是一个充满烦恼的过程.

Why not simply try running it? If you're going to deal with Busybox-based systems, lots of the executables can't be found by searching — they're built into the shell. The major caveat is if a command does something dangerous when run with no arguments — but very few POSIX commands, if any, do that. You might also need to determine what command exit statuses indicate that the command is not found versus the command objecting to not being called with appropriate arguments. And there's little guarantee that all systems will be consistent on that. It's a fraught process, in case you hadn't gathered.

#!/usr/bin/env perl
#
# @(#)$Id: pathfile.pl,v 3.4 2015/10/16 19:39:23 jleffler Exp $
#
# Which command is executed

# Loosely based on 'which' from Kernighan & Pike "The UNIX Programming Environment"

#use v5.10.0;    # Uses // defined-or operator; not in Perl 5.8.x
use strict;
use warnings;
use Getopt::Std;
use Cwd 'realpath';
use File::Basename;

my $arg0 = basename($0, '.pl');
my $usestr = "Usage: $arg0 [-AafhqrsVwx] [-p path] command ...\n";
my $hlpstr = <<EOS;

  -A       Absolute pathname (determined by realpath)
  -a       Print all possible matches
  -f       Print names of files (as opposed to symlinks, directories, etc)
  -h       Print this help message and exit
  -q       Quiet mode (don't print messages about files not found)
  -r       Print names of files that are readable
  -s       Print names of files that are not empty
  -V       Print version information and exit
  -w       Print names of files that are writable
  -x       Print names of files that are executable
  -p path  Use PATH
EOS

sub usage
{
    print STDERR $usestr;
    exit 1;
}

sub help
{
    print $usestr;
    print $hlpstr;
    exit 0;
}

sub version
{
    my $version = 'PATHFILE Version $Revision: 3.4 $ ($Date: 2015/10/16 19:39:23 $)';
    # Beware of RCS hacking at RCS keywords!
    # Convert date field to ISO 8601 (ISO 9075) notation
    $version =~ s%\$(Date:) (\d\d\d\d)/(\d\d)/(\d\d) (\d\d:\d\d:\d\d) \$%\$$1 $2-$3-$4 $5 \$%go;
    # Remove keywords
    $version =~ s/\$([A-Z][a-z]+|RCSfile): ([^\$]+) \$/$2/go;
    print "$version\n";
    exit 0;
}

my %opts;
usage   unless getopts('AafhqrsVwxp:', \%opts);
version if ($opts{V});
help    if ($opts{h});
usage   unless scalar(@ARGV);

# Establish test and generate test subroutine.
my $chk = 0;
my $test = "-x";
my $optlist = "";
foreach my $opt ('f', 'r', 's', 'w', 'x')
{
    if ($opts{$opt})
    {
        $chk++;
        $test = "-$opt";
        $optlist .= " -$opt";
    }
}
if ($chk > 1)
{
    $optlist =~ s/^ //;
    $optlist =~ s/ /, /g;
    print STDERR "$arg0: mutually exclusive arguments ($optlist) given\n";
    usage;
}
my $chk_ref = eval "sub { my(\$cmd) = \@_; return -f \$cmd && $test \$cmd; }";

my @PATHDIRS;
my %pathdirs;
my $path = defined($opts{p}) ? $opts{p} : $ENV{PATH};
#foreach my $element (split /:/, $opts{p} // $ENV{PATH})
foreach my $element (split /:/, $path)
{
    $element = "." if $element eq "";
    push @PATHDIRS, $element if $pathdirs{$element}++ == 0;
}

my $estat = 0;
CMD:
foreach my $cmd (@ARGV)
{
    if ($cmd =~ m%/%)
    {
        if (&$chk_ref($cmd))
        {
            print "$cmd\n" unless $opts{q};
            next CMD;
        }
        print STDERR "$arg0: $cmd: not found\n" unless $opts{q};
        $estat = 1;
    }
    else
    {
        my $found = 0;
        foreach my $directory (@PATHDIRS)
        {
            my $file = "$directory/$cmd";
            if (&$chk_ref($file))
            {
                $file = realpath($file) if $opts{A};
                print "$file\n" unless $opts{q};
                next CMD unless defined($opts{a});
                $found = 1;
            }
        }
        print STDERR "$arg0: $cmd: not found\n" unless $found || $opts{q};
        $estat = 1;
    }
}

exit $estat;

这篇关于如何找出命令是否以POSIX兼容的方式存在?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆