Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何判断脚本是否从管道执行?_Bash_Shell_Sh - Fatal编程技术网

Bash 如何判断脚本是否从管道执行?

Bash 如何判断脚本是否从管道执行?,bash,shell,sh,Bash,Shell,Sh,假设我们有一个简单的脚本(selfie.sh): 我如何判断它是否以这种方式执行sh selfie.sh, 例如cat selfie.sh | sh sh selfie.sh selfie.sh 和cat selfie.sh | sh输出以下内容: sh 我所尝试的: [-s“$0”]如果在pwd $BASH_SOURCE或类似的东西与POSIXshell不兼容 这个问题摆在我面前,因为我写了一个名为的项目,我希望用户在第一次安装时可以这样安装: curl -L https://raw.

假设我们有一个简单的脚本(selfie.sh):

我如何判断它是否以这种方式执行
sh selfie.sh
, 例如
cat selfie.sh | sh

sh selfie.sh

selfie.sh
cat selfie.sh | sh
输出以下内容:

sh
我所尝试的:

  • [-s“$0”]
    如果在
    pwd
  • $BASH_SOURCE
    或类似的东西与POSIXshell不兼容
这个问题摆在我面前,因为我写了一个名为的项目,我希望用户在第一次安装时可以这样安装:

curl -L https://raw.githubusercontent.com/oxnz/shell-utils/master/tool/install | sh
但是,如果他已经有了软件的副本,并且像这样从shell调用:

sh shell-utils/tool/install.sh

我需要说出不同之处,并采取不同的行动。

尝试
-t
条件表达式

$ cat selfie.sh
[ -t 0 ] && echo "bash is reading a script from somewhere else" || echo "bash is reading a script from stdin"
$ cat selfie.sh | sh
bash is reading a script from stdin
$ sh selfie.sh
bash is reading a script from somewhere else

您可以使用以下与POSIX兼容的shell函数

唯一的先决条件是Unix平台,其中
stdin
表示为文件
/dev/stdin
,这通常是当前的情况

只有在一种非常不寻常的情况下才会出现误报:如果在获取脚本的同时,还提供管道输入;e、 例如,
echo hi |。selfie.sh

#!/bin/sh

# Indicates via exit code whether the contents of the script at hand
# were provided through a pipe, e.g., `curl .... | sh`.
# Caveat: You'll get a false positive in the following - exotic - corner case:
#         ... | . script # combination of pipeline input and sourcing.
isThisScriptPiped() {
  if [ ! -f "$0" ] || [ -x "$0" ] && POSIXLY_CORRECT=1 file -- "$0" | grep -Fvq 'text'; then
    if POSIXLY_CORRECT=1 file -i /dev/stdin | grep -Fq 'fifo'; then
      return 0
    fi
  fi
  return 1
}

# Sample call
isThisScriptPiped && echo 'PIPED' || echo 'NOT piped'
以下是同一功能的注释版本:

#!/bin/sh

# Note: POSIXLY_CORRECT is set below to make the GNU `file` utility behave
#       in a POSIX-compliant manner so as to report the type of the *target*
#       in the event that the operand is a *symlink*.
#       This *could* happen with a shell executable that is a symlink, and 
#       *definitely* happens with /dev/stdin, which on Linux is a symlink to
#       /proc/self/fd/0.

# Indicates via exit code whether the contents of the script at hand
# were provided through a pipe, e.g., `curl .... | sh`.
# Caveat: You'll get a false positive in the following - exotic - corner case:
#         ... | . script # combination of pipeline input and sourcing.
isThisScriptPiped() {

  # Test 1 of 2: Check if $0 refers to:
  #  either: a nonexisting file (implies that $0 refers to an executable in
  #          the path)
  #  or: an executable file that is not text-based (not a shell script)
  # Both cases imply that $0 refers to a shell executable, which in turn implies
  # that no filename argument (script file path) was passed to the shell.
  # Note that while `file` implementations differ, their output for text-based
  # executables (shell scripts) always contains 'text' (POSIX mandates
  # 'commands text', but neither BSD nor GNU `file` do that).
  if [ ! -f "$0" ] || [ -x "$0" ] && POSIXLY_CORRECT=1 file -- "$0" | grep -Fvq 'text'; then

    # The implication is that the script contents comes from:
    #  - either: stdin - whether through input redirection (sh < script) or
    #            from a pipe (... | sh)
    #  - or: from sourcing (. script)
    # Note that in sh there is no way that I know of that lets you determine
    # reliably whether the script is being sourced. Knowing whether the script
    # is being sourced *or* provided via stdin is as close as you can get.
    # (To check for sourcing in Bash, Ksh, or Zsh, see 
    #  http://stackoverflow.com/a/28776166/45375 )

    # Test 2 of 2:
    #  See if stdin is connected to a pipe, which in combination with test 1
    #  implies that the script contents is being piped, EXCEPT in one scenario:
    #  Caveat: You'll get a false positive in the following - very unusual - 
    #          corner case:
    #            ... | . script # combination of sourcing and pipe input
    #  Note:
    #    - POSIX mandates that when passing a FIFO (named pipe) to `file`
    #      the output contain the string 'fifo', which is true of both BSD
    #      and GNU `file`.
    #    - Option -i is crucial to prevent `file` from trying to
    #      read the *contents* of stdin; with -i, it just reports the basic
    #      file type.
    if POSIXLY_CORRECT=1 file -i /dev/stdin | grep -Fq 'fifo'; then
      return 0
    fi

  fi

  return 1

}

# Sample call
isThisScriptPiped && echo 'PIPED' || echo 'NOT piped'
#/垃圾箱/垃圾箱
#注意:下面设置POSIXLY_CORRECT以使GNU`file`实用程序正常工作
#以符合POSIX的方式报告*目标的类型*
#如果操作数是*符号链接*。
#这*可能*发生在作为符号链接的shell可执行文件上,并且
#*肯定*发生在/dev/stdin上,它在Linux上是到的符号链接
#/proc/self/fd/0。
#通过退出代码指示当前脚本的内容是否
#是通过管道提供的,例如,“curl…”嘘。
#警告:在以下情况下,您将得到假阳性:
#         ... | . 脚本#管道输入和来源的组合。
isThisScriptPiped(){
#测试1/2:检查$0是否指:
#或者:不存在的文件(意味着$0引用中的可执行文件)
#(路径)
#或:非基于文本的可执行文件(非shell脚本)
#这两种情况都意味着$0引用shell可执行文件,这反过来又意味着
#没有向shell传递任何文件名参数(脚本文件路径)。
#请注意,虽然“file”实现有所不同,但它们的输出是基于文本的
#可执行文件(shell脚本)始终包含“文本”(POSIX命令)
#“命令文本”,但BSD和GNU“文件”都不这样做)。
如果[!-f“$0”]|【-x“$0”]&&POSIXLY\u CORRECT=1文件--“$0”| grep-Fvq‘text’;则
#这意味着脚本内容来自:
#-或者:stdin-无论是通过输入重定向(sh
你能编辑你的Q来扩展你为什么需要/想要这样做吗?直接从
curl
执行代码是一种安全风险,因为在执行之前你没有机会验证远程服务器实际发送的内容。如果答案解决了你的问题,请单击大复选标记接受它(✓) 在它旁边。如果您发现其他答案有帮助,请向上投票。接受和向上投票答案不仅有助于回答的人,也有助于未来的读者。请查看。如果您的问题尚未完全回答,请提供反馈。谢谢,但是
sh selfie.sh
将失败
[-t 0]
test.@oxnz正如你所说,这个解决方案并不完美,但我认为这是唯一的办法。@oxnz,然后尝试
[-t0]&&[-t1]
-检查
stdin
stdout
@Dummy00001:这没有帮助,因为
stdout
在这两种情况下都会连接到终端。对不起,我的意思是
[-t0].[-t1]
。或者更准确地说,
{[-t0]||][-t1]}| |……
#!/bin/sh

# Note: POSIXLY_CORRECT is set below to make the GNU `file` utility behave
#       in a POSIX-compliant manner so as to report the type of the *target*
#       in the event that the operand is a *symlink*.
#       This *could* happen with a shell executable that is a symlink, and 
#       *definitely* happens with /dev/stdin, which on Linux is a symlink to
#       /proc/self/fd/0.

# Indicates via exit code whether the contents of the script at hand
# were provided through a pipe, e.g., `curl .... | sh`.
# Caveat: You'll get a false positive in the following - exotic - corner case:
#         ... | . script # combination of pipeline input and sourcing.
isThisScriptPiped() {

  # Test 1 of 2: Check if $0 refers to:
  #  either: a nonexisting file (implies that $0 refers to an executable in
  #          the path)
  #  or: an executable file that is not text-based (not a shell script)
  # Both cases imply that $0 refers to a shell executable, which in turn implies
  # that no filename argument (script file path) was passed to the shell.
  # Note that while `file` implementations differ, their output for text-based
  # executables (shell scripts) always contains 'text' (POSIX mandates
  # 'commands text', but neither BSD nor GNU `file` do that).
  if [ ! -f "$0" ] || [ -x "$0" ] && POSIXLY_CORRECT=1 file -- "$0" | grep -Fvq 'text'; then

    # The implication is that the script contents comes from:
    #  - either: stdin - whether through input redirection (sh < script) or
    #            from a pipe (... | sh)
    #  - or: from sourcing (. script)
    # Note that in sh there is no way that I know of that lets you determine
    # reliably whether the script is being sourced. Knowing whether the script
    # is being sourced *or* provided via stdin is as close as you can get.
    # (To check for sourcing in Bash, Ksh, or Zsh, see 
    #  http://stackoverflow.com/a/28776166/45375 )

    # Test 2 of 2:
    #  See if stdin is connected to a pipe, which in combination with test 1
    #  implies that the script contents is being piped, EXCEPT in one scenario:
    #  Caveat: You'll get a false positive in the following - very unusual - 
    #          corner case:
    #            ... | . script # combination of sourcing and pipe input
    #  Note:
    #    - POSIX mandates that when passing a FIFO (named pipe) to `file`
    #      the output contain the string 'fifo', which is true of both BSD
    #      and GNU `file`.
    #    - Option -i is crucial to prevent `file` from trying to
    #      read the *contents* of stdin; with -i, it just reports the basic
    #      file type.
    if POSIXLY_CORRECT=1 file -i /dev/stdin | grep -Fq 'fifo'; then
      return 0
    fi

  fi

  return 1

}

# Sample call
isThisScriptPiped && echo 'PIPED' || echo 'NOT piped'