如何知道什么是命令、系统调用、bash 内置函数等?

如何知道什么是命令、系统调用、bash 内置函数等?

最近有同事问“什么是man”?得知此事后并非所有可从 Bash CLI 访问的内容都是命令,我小心翼翼地呼叫man命令。

man man只是称其为接口:

NAME
       man - an interface to the on-line reference manuals

man有一个可执行文件:

$ which man
/usr/bin/man
$ file /usr/bin/man
/usr/bin/man: ELF 64-bit LSB shared object

man程序也是如此吗,因为它有可执行文件?还可以是哪些其他名词man?什么名词最能描述它?真的,我对一般情况感兴趣可以确定什么thing on the cli是任意的,man这只是一个例子。

就此而言,可以在 Bash CLI 上使用的所有内容用什么词来表示?一个包含命令、别名、系统调用等的词?

答案1

在 POSIX 术语中,任何可以要求 shell 做某事的东西都是一个命令

指示 shell 执行特定任务的指令。

所以

man man

是一个命令,按原样(技术上)

man

man也是一个实用程序

一种程序,不包括作为 Shell 命令语言的一部分提供的特殊内置实用程序,可以从 shell 中按名称调用该程序来执行特定任务或相关任务集。

(排除在这里并不重要;提到它是因为特殊的内置实用程序具有特定的属性.)

要找出给定命令是什么,请使用type.这将告诉您它是否是内置的,或者是一个程序PATH(以及在哪里),或者是一个别名等(或未知)。

请注意,系统调用不能用作 shell 命令。

也可以看看它们是命令还是实用程序?内置命令和非内置命令有什么区别?

答案2

从最底层开始:

系统调用

系统调用是用户态任务(必须)用来从内核请求某些服务并运行到特权内核模式的方式。

假设您的编程语言是 C,并且您希望任务更改其当前目录,您将需要插入chdir()指令到您的程序中。

当然这些程序是不立即可从命令行访问。 vg 在命令行中输入 chdir 不会调用 chdir 系统调用。

所有可用系统调用的列表当然取决于内核,唯一可靠的来源当然是include/linux/syscalls.h内核源代码发行版的头文件。

指示

CLI 是您正在运行的任务的界面。无论您输入什么,都称为操作说明只是因为它应该指示任务完成某些操作。

命令

您输入的内容将首先通过解释器,该解释器将对您输入的标记执行一些词法分析,并且在 shell 的特定情况下,可能会识别一个名称命令(理解为不是变量赋值)并顺便决定它需要诉诸另一个程序才能实现您的请求。然后它将派生一个子进程,该子进程将执行另一个程序的二进制文件。

但在某些特殊情况下,任务可能会更容易地满足请求,而无需求助于外部程序(例如简单的微积分),或者更重要的是,必须在内部执行您的请求。

内置命令

回到我们最初更改活动目录的意愿,用户将发出众所周知的 shell 命令cd。用户真正想要的是更改其 shell 的当前目录。而且由于 chdir 系统调用仅更改调用者的当前工作目录,因此 shell 无法派生另一个不会对其父级进行任何更改的进程。 shell 必须在内部执行 chdir 系统调用。

yourshellname所有手册页中都列出了 shell 内置命令。

别名

别名只不过是任何用户都可以设置的同义词,并且将由命令行解释器翻译成所需的字符串(应该代表 shell 的任何合法指令。)

通过 shell 内置alias命令可以获得所有当前活动别名的列表。

答案3

我有一个小 shellscript,它可以帮助我识别命令:它是什么类型的命令以及如果通过程序包安装,是哪个包。也许用这个名字what-about

#!/bin/bash

LANG=C
inversvid="\0033[7m"
resetvid="\0033[0m"

if [ $# -ne 1 ]
then
 echo "Usage: ${0##*/} <program-name>"
 echo "Will try to find corresponding package"
 echo "and tell what kind of program it is"
 exit 1
fi
command="$1"

str=;for ((i=1;i<=$(tput cols);i++)) do str="-$str";done
tmp="$command"
first=true
curdir="$(pwd)"
tmq=$(which "$command")
tdr="${tmq%/*}"
tex="${tmq##*/}"
if test -d "$tdr"; then cd "$tdr"; fi
#echo "cwd='$(pwd)' ################# d"

while $first || [ "${tmp:0:1}" == "l" ]
do
 first=false
 tmp=${tmp##*\ }
 tmq="$tmp"
 tmp=$(ls -l "$(which "$tmp")" 2>/dev/null)
 tdr="${tmq%/*}"
 tex="${tmq##*/}"
 if test -d "$tdr"; then cd "$tdr"; fi
# echo "cwd='$(pwd)' ################# d"
 if [ "$tmp" == "" ]
 then
  tmp=$(ls -l "$tex" 2>/dev/null)
  tmp=${tmp##*\ }
  if [ "$tmp" == "" ]
  then
   echo "$command is not in PATH"
#   package=$(bash -ic "$command -v 2>&1")
#   echo "package=$package XXXXX 0"
   bash -ic "alias '$command' > /dev/null 2>&1" > /dev/null 2>&1
   if [ $? -ne 0 ]
   then
    echo 'looking for package ...'
    package=$(bash -ic "$command -v 2>&1"| sed -e '0,/with:/d'| grep -v '^$')
   else
    echo 'alias, hence not looking for package'
   fi
#   echo "package=$package XXXXX 1"
   if [ "$package" != "" ]
   then
    echo "$str"
    echo "package: [to get command '$1']"
    echo -e "${inversvid}${package}${resetvid}"
   fi
   else
    echo "$tmp"
   fi
 else
  echo "$tmp"
 fi
done
tmp=${tmp##*\ }
if [ "$tmp" != "" ]
then
 echo "$str"
 program="$tex"
 program="$(pwd)/$tex"
 file "$program"
 if [ "$program" == "/usr/bin/snap" ]
 then
  echo "$str"
  echo "/usr/bin/snap run $command     # run $command "
  sprog=$(find /snap/"$command" -type f -iname "$command" \
   -exec file {} \; 2>/dev/null | sort | tail -n1)
  echo -e "${inversvid}file: $sprog$resetvid"
  echo "/usr/bin/snap list $command    # list $command"
  slist="$(/usr/bin/snap list "$command")"
  echo -e "${inversvid}$slist$resetvid"
 else
  package=$(dpkg -S "$program")
  if [ "$package" == "" ]
  then
   package=$(dpkg -S "$tex" | grep -e " /bin/$tex$" -e " /sbin/$tex$")
   if [ "$package" != "" ]
   then
    ls -l /bin /sbin
   fi
  fi
  if [ "$package" != "" ]
  then
   echo "$str"
   echo " package: /path/program  [for command '$1']"
   echo -e "${inversvid} $package ${resetvid}"
  fi
 fi
fi
echo "$str"
#alias=$(grep "alias $command=" "$HOME/.bashrc")
alias=$(bash -ic "alias '$command' 2>/dev/null"| grep "$command")
if [ "$alias" != "" ]
then
 echo "$alias"
fi
type=$(type "$command" 2>/dev/null)
if [ "$type" != "" ]
then
 echo "type: $type"
elif [ "$alias" == "" ]
then
 echo "type: $command: not found"
fi
cd "$curdir"

有时有两种选择,例如 for echo,既是单独编译的程序,又是 shell 内置命令。除非您使用单独程序的完整路径,否则内置的 shell 将获得优先级并被使用,

$ what-about echo
-rwxr-xr-x 1 root root 35000 jan 18  2018 /bin/echo
----------------------------------------------------------------------------------
/bin/echo: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0,
BuildID[sha1]=057373f1356c861e0ec5b52c72804c86c6842cd5, stripped
----------------------------------------------------------------------------------
 package: /path/program  [for command 'echo']
 coreutils: /bin/echo 
----------------------------------------------------------------------------------
type: echo is a shell builtin

有时命令链接到可能隐藏的程序,例如rename我使用的版本,

$ what-about rename
lrwxrwxrwx 1 root root 24 maj 12  2018 /usr/bin/rename -> /etc/alternatives/rename
lrwxrwxrwx 1 root root 20 maj 12  2018 /etc/alternatives/rename -> /usr/bin/file-rename
-rwxr-xr-x 1 root root 3085 feb 20  2018 /usr/bin/file-rename
----------------------------------------------------------------------------------
/usr/bin/file-rename: Perl script text executable
----------------------------------------------------------------------------------
 package: /path/program  [for command 'rename']
 rename: /usr/bin/file-rename 
----------------------------------------------------------------------------------
type: rename is /usr/bin/rename

为了避免错误,我有一个别名rm,并且别名优先于PATH.您可以使用反斜杠作为前缀,\rm以跳过别名并直接运行程序。 (请记住,别名仅适用于特定用户,不适用于sudo其他用户,除非他们定义了类似的别名。)

$ what-about rm
-rwxr-xr-x 1 root root 63704 jan 18  2018 /bin/rm
---------------------------------------------------------------------------
/bin/rm: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for
GNU/Linux 3.2.0, uildID[sha1]=864c9bbef111ce358b3452cf7ea457d292ba93f0,
stripped
---------------------------------------------------------------------------
 package: /path/program  [for command 'rm']
 coreutils: /bin/rm 
---------------------------------------------------------------------------
alias rm='rm -i'
type: rm is /bin/rm

相关内容