我如何检测用户输入是来自管道还是带有参数? (如使用“if else”)

我如何检测用户输入是来自管道还是带有参数? (如使用“if else”)

我如何检测用户输入是来自管道还是带有参数? (如使用“if else”)

例子:

有管道

$ cat input_file | ./example.sh
hello
world

带参数

$ ./example.sh "hello" "world"
hello
world

我的错误代码:

我写了 url slug shell 脚本。我在脚本中有一个用于 url 解析的函数。我将该函数用于管道cat a | ./example.sh或用户输入./example.sh "hello" "world"。我的代码是正确的,但我不明白如何检测和检查用户输入是管道或参数。

对不起我的英语

#!/bin/bash

# define replacements
declare -a repls=(
    "Ğg"
    "ğg"
    "Çc"
    "çc"
    "Şs"
    "şs"
    "Üu"
    "üu"
    "Öo"
    "öo"
    "İi"
    "ıi"
    " -"
    "--"
)

function slug() {
    slug=""

    for (( i=0; i<${#arg}; i++ )) 
    do
        char="${arg:$i:1}"
        ascii=$(printf "%d" "'$char")

        # if alphanumeric
        # locale encoding should be UTF-8 for this values to work
        if [[ ( $ascii -ge 48 && $ascii -le 57 ) || # numbers
            ( $ascii -ge 65 && $ascii -le 90 ) ||  # uppercase
            ( $ascii -ge 97 && $ascii -le 122 ) ]]; then # lowercase
            slug="$slug$char"
        else
            for (( j=0; j < ${#repls[@]}; j++ ))
            do
                from=${repls[$j]:0:1}
                to=${repls[$j]:1:1}
                if [[ $char == $from ]]; then
                    slug="$slug$to"
                    break
                fi
            done
        fi
    done

    if [[ $slug == "" ]]; then
        echo "words should contain at least one valid character"
        exit 1
    fi

    echo $slug | awk '{print tolower($0)}'
}

#FOR PARAMETERS
for arg in "$@"
do
 slug;
done

##FOR READ PIPE
[[ -z "$@" ]] && while read arg;
do
 slug;    
done

答案1

我会做:

something_with() {
  printf 'Processing "%s"\n' "$1"
}

ret=0
if [ "$#" -gt 0 ]; then
  # process args on command line

  for arg do
    something_with "$arg" || ret=$?
  done
else
  # no arg, processing lines of stdin instead:

  while IFS= read -r "$arg" || [ -n "$arg" ]; do
    # redirect something_with's stdin to /dev/null to make sure
    # it doesn't interfere with the list of args.
    </dev/null something_with "$arg" || ret=$?
  done
fi

exit "$ret"

(请注意,这意味着通过 stdin 发送的参数不能包含换行符)。

虽然您也可以只将输入作为参数,但将脚本调用为:

xargs -rd '\n' -a input_file your-script

(这里假设 GNU xargs),用于xargs将行的内容input_file作为参数传递给your-script(在这种情况下your-script可以多次调用以xargs解决命令参数最大数量的限制)。

无论如何,我想说你不想在这里检查 stdin 是否是管道。

  1. 首先这cat input_file | your-script是一个猫的无用使用(臭名昭著的UUoC)。通常,如果您想将文件的内容作为命令的输入,可以使用< input_file your-scripor your-script < input_file,在这种情况下,脚本的标准输入将不是管道(除非input_file它本身是命名管道)。

  2. 您的脚本可以使用与管道连接的标准输入来调用,即使您不希望它读取它,例如在ssh host your-script arg1 arg2(where stdin aa pipeline to sshd) 或... | while IFS= read -r foo; do your-script "x$foo"; doneor cmd | xargs your-script(使用某些xargs实现;某些将标准输入重定向到 /dev/null那里)。

但如果你真的想这样做,这个网站上的一个单独的问题已经解决了这个问题:程序如何知道 stdout 是否连接到终端或管道?不同之处在于这里是 stdin 而不是 stdout,因此文件描述符是 0 而不是 1。

答案2

$-您可以通过变量或通过变量检查您的 shell 是否是交互式的$PS1

case "$-" in
*i*)    echo This shell is interactive ;;
*)  echo This shell is not interactive ;;
esac

或者

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

上面的例子是复制自这里

感谢@Kusalananda:检查参数是否通过管道传输到脚本中的另一个选项:

if [ -t 0 ]; then
  echo "This shell is interactive"
fi

相关内容