Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.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
Linux 问题控制脚本流_Linux_Shell_Scripting - Fatal编程技术网

Linux 问题控制脚本流

Linux 问题控制脚本流,linux,shell,scripting,Linux,Shell,Scripting,我对shell脚本还不熟悉,我的脚本看起来不错,但我在控制流程方面遇到了问题。有人能指出我犯了什么愚蠢的错误吗 #! /bin/sh echo "Are you sure youx want to delete $1? Answer y or n" read ans echo $ans if $ans = "y"|"Y" then mv $1 /home/parallels/dustbin echo "File $1 has been deleted" else echo "F

我对shell脚本还不熟悉,我的脚本看起来不错,但我在控制流程方面遇到了问题。有人能指出我犯了什么愚蠢的错误吗

#! /bin/sh

echo "Are you sure youx want to delete $1? Answer y or n"
read ans
echo $ans
if $ans = "y"|"Y"
then
    mv $1 /home/parallels/dustbin
    echo "File $1 has been deleted"
else echo "File $1 has not been deleted"
fi

使您的if条件如下:

if [ "$ans" = "y" -o "$ans" = "Y" ]

您还可以将用户响应转换为任意一种情况,只需检查相应的情况,如

read ans
ans=${ans,,}  # make 'ans' lowercase, or use ${ans^^} for making it uppercase
if [ "$ans" = "y" ]
then
   ....
fi

你的脚本有一些地方不对劲。有些是严重的,有些则不那么严重

第一,严重的问题

正如古鲁所建议的,您需要使用方括号来包围您的
if
条件。这是因为
如果
只测试条件的输出,它不会执行实际的字符串比较。传统上,一个名为
/bin/test
的程序(也称为
/bin/[
的程序)会处理这个问题。现在,这个功能内置在shell中,但
/bin/sh
仍然像是一个单独的程序一样运行

事实上,如果你不使用方括号来表示你的病情,你可以用
if
做一些有趣的事情。例如,
如果grep-q'RE'/path/to/file;那么
是很常见的。
grep-q
命令不发出输出,只返回一个由
if
检测到的“成功”或“失败”

第二个严重问题是,您正在回显一个状态,该状态可能是真的,也可能不是真的。我认为这是一个严重问题,因为……好吧,日志消息不应该做出错误的声明。如果
$1
中的文件权限错误,或者文件名包含空格,则
mv
命令将失败,但消息将失败声称它没有。稍后会详细介绍

其次是不太严重的问题

这些都是风格和优化方面的东西

首先,在大多数平台上,
read
包含一个
-p
选项,用于指定提示。使用该选项,您不需要包含
echo
命令

其次,如果
结构正在包装,缩进会使您很难看到
结构是什么。这在这么小的程序中不是一个大问题,但随着您的成长,您确实希望遵循一致的标准

第三,如果您使用
case
语句而不是
if
语句,您可能会在这样的选择题中获得更大的灵活性

在所有这些之后,下面是我如何编写这个脚本:

#!/bin/sh

if [ "$1" = "-y" ]; then
  ans=y
  shift
elif [ -t 0 ]; then
  read -p "Are you sure you want to delete '$1' (y/N) ? " ans
fi

case "$ans" in
  Y*|y*)
    retval=0
    if [ -z "$1" ]; then
      retval=64
      echo "ERROR: you didn't specify a filename." >&2
    if [ ! -f "$1" ]; then
      retval=66
      echo "ERROR: file '$1' not found!" >&2
    elif mv "$1" /home/parallels/dustbin/; then
      echo "File '$1' has been deleted" >&2
    else
      retval=$?
      echo "ERROR: file '$1' could not be deleted!" >&2
    fi
    ;;
  *)
    echo "ABORT: file '$1' has not been deleted" >&2
    retval=4
    ;;
esac

exit $retval
除了上面提到的内容外,此代码段中还有一些内容:

  • [“$1”=“-y”]
    -如果用户指定了一个
    -y
    选项,那么我们的行为就好像问题的答案是“是”
  • [-t0]
    -这测试我们是否在交互终端上。如果在交互终端上,那么用
    阅读
    提问是有意义的
  • Y*| Y*)
    -在case语句中,它匹配以大写或小写“Y”开头的任何字符串。因此,有效的肯定回答将是“Y”、“yes”、“yellow”等
  • [!-f“$1”]
    -此测试文件是否存在。您可以
    man test
    man sh
    查看shell中可用的各种测试。(
    -f
    可能不是最适合您的。)
  • &2
    -在一行的末尾,将其输出发送到“标准错误”而不是“标准输出”。这改变了管道、cron等处理输出的方式。错误和日志数据通常发送到stderr,以便stdout可以专用于程序的实际输出
  • mv“$1”…
    -文件名用引号括起来。如果文件名中有空格等特殊字符,这将为您提供保护
  • $retval
    -此项的值来自对中最近项的最佳猜测
  • retval=$?
    -这是最近执行的命令的退出状态。在这种情况下,这意味着我们将
    mv
    的退出状态分配给变量
    $retval
    ,因此如果
    mv
    失败,整个脚本将报告失败的原因,只要
    mv

    • 下面是包含错误处理的完美代码

      #!/bin/sh
      
      echo "Are you sure you want to delete $1? Answer y or n"
      read ans
      echo $ans
      
      if [ $ans == "y" ] || [ $ans == "Y" ]
      then
          if [ -f $1 ]
          then
                 mv $1 /home/parallels/dustbin
                 echo "File $1 has been deleted"         
          else
                 echo " File $1 is not found"
          fi
      else 
          echo "File $1 has not been deleted"
      fi
      

      感谢您快速而有用的回答!欢迎您。如果解决方案对您有效,请接受答案。如果有多个答案对您有效,请接受最适合您问题的答案…我唯一的问题是,如果
      mv
      失败,是否还需要从脚本返回错误代码(这目前被
      echo错误隐藏。
      返回ok)@GermanGarcia-是的,这可能是个好主意,特别是如果脚本是精心编制的,可以由其他脚本包装。我已更新了答案,以包含更多“学习”。-)很好的教学答案。干杯。这种转换成小写的方法只在bash中有效。OP的脚本运行
      /bin/sh
      -我们不知道bash是否也可用,但即使可用,您的答案可能也应该将bash指定为需求,因为bash在作为
      sh
      调用时使用POSIX行为。