Shell脚本中的嵌套if

3
我想编写一个脚本,它接受1个命令行参数(目录),然后提示输入2个数字,然后打印出大小在这两个数字之间的任何文件(每个文件占据一行)。以下是我的脚本:
echo -n "Enter the first number: "
read a
echo -n "Enter the second, bigger number: "
read b
    if
 [ $b -lt $a ]
then
 echo 'The first number must be smaller'
else
 echo The files in $1 that are between $a and $b bytes are the following
 echo
 for var in 'ls $1'
 do
  if
   [ -f $var ]
  then
    size='ls -l $var | '{ print $5 }''
     if
      [ $size -le $b && $size -ge $a ]
     then
      echo $var is $size bytes
     fi
  fi
 done
fi

问题在于我输入数字后,它会打印出“The files...”,然后什么也不做。此外,我使用Vi进行编辑,但是最后三行的颜色不太对(颜色应该与第一个“fi”匹配,但实际上不匹配)。有人能告诉我错在哪里吗?谢谢。

1
你需要在脚本的最顶部添加一个"Shebang"行。你应该有#!/bin/ksh或者#!/bin/bash,或者从echo $SHELL获取到的任何值。并且你会发现大多数问题都可以通过设置shell调试/跟踪选项来运行此代码来解决。只需在echo -n ...之前添加set -vx即可。调试显示每个代码块在执行之前,以及带有前导+符号的每行从该块中执行的代码行,包括变量的值。你应该看到$size不是你想象中的那样。祝你好运。 - shellter
为什么我需要那个哈希行?我已经快速阅读了相关内容,但仍然不明白为什么需要它。非常感谢,我不知道这里有一个调试器 :) - Nguyễn Duy
@NguyễnDuy 你应该包含 #!/bin/??sh 这一行,从而声明你需要运行脚本的 shell。如果它与传统的 Bourne shell 兼容,则可以使用 #!/bin/sh,但如果你正在使用仅在 zsh 或 bash 中可用的功能(内置),则应使用 #!/bin/bash#!/bin/zsh - 或者其他。你还可以编写以 #!/usr/bin/perl 开头的 Perl 脚本,然后 chmod +x myPerlScript,而无需在文件上使用如 .pl 这样的扩展名。 - Stephen P
3个回答

2

你当前的问题是在需要命令替换处使用了单引号。但是,这种方式不是遍历文件的正确方法。应该使用模式匹配代替。你的for循环应该如下:

for var in $1/*
do
  if [ -f "$var" ]
  then
    # Check 'man stat' for the correct format string on your system
    size=$(stat +%s "$var")
    if [ $size -le $b ] &&  [ $size -ge $a ]
    then
      echo $var is $size bytes
    fi
  fi
done

1
如其他人所述,使用shebang并在命令中使用反引号。其他错误包括ls -l $var | '{ print $5 }'应为ls -l "$1$var" | awk '{ print $5 }'(缺少awk命令),在测试文件时应该使用文件的完整路径,例如[ -f "$1$var" ],因为用户可能不在与脚本提供的路径相同的目录中。另一个问题是[ $size -le $b && $size -ge $a ]。不能以这种方式使用&&运算符,而应改用[ $size -le $b ] && [ $size -ge $a ]
这些是我对您的代码所做的所有更改。希望能对您有所帮助。
echo -n "Enter the first number: "
read a
echo -n "Enter the second, bigger number: "
read b
if [ $b -lt $a ]
then
  echo 'The first number must be smaller'
else
  echo The files in "$1" that are between "$a" and "$b" bytes are the following
  echo
  for var in `ls "$1"`
  do
    if [ -f $1$var ]
    then
      size=`ls -l "$1$var" | awk '{ print $5 }'`
      if [ $size -le $b ] && [ $size -ge $a ]
      then
        echo "$var" is "$size" bytes
      fi
    fi
  done
fi

1
这里有几个问题,但我认为让你卡住的是单引号(')在一些应该使用重音符号(`)的地方被使用了。这是一个微妙的排版区别,所以有时候那些没有遇到过它的人不会注意到这个区别。在我的键盘上,按下数字1左侧的键可以获得一个重音符号,它与波浪号(~)配对,但你的键盘可能不同。
重音符号允许你将命令的输出分配给一个变量,例如:
my_variable=`ls - l` # <- uses backtick, assigns output of 'ls -l' command to $my_variable

#As opposed to:
my_variable='ls -l' # <- uses single-quote, makes $my_variable equal to the text "ls -l"

请注意,如果您将正确的单引号替换为反引号,则这也将解决您的vi问题。

1
最好使用更具视觉特色的 $(ls -l),而不是反引号。 - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接