【问题标题】:Bash script - Adding/Subtracting 1 from fileBash 脚本 - 从文件中添加/减去 1
【发布时间】:2017-04-10 12:47:36
【问题描述】:

这就是我想要做的:

我想制作一个脚本,我可以使用counter_use incounter_use out 调用它。如果我输入in,我想要一个计数器为名为“counter”的文件中的数值加1,如果我输入out,我想从文件中减去1。

如果计数器中的值等于或大于 1,我还希望脚本输出 Logged in,如果计数器等于 0,则输出 Not logged in

如果我将计数器硬编码为特定数字,则最后一部分将运行。问题是第一部分。

echo "In or out?"

read input > counterFile

if grep -q "in" counterFile
    then //what should I do here so that it adds +1 to a file called 
counter?

elif grep -q "out" counterFile
    then //what should I do here so that it subtracts -1 to a file called 
counter?

if [ $counter -ge 1 ]
    then
        echo "Logged in"

elif [ $counter -eq 0 ]
    then
        echo "Not logged in"

else
        echo "Wrong input"

fi

【问题讨论】:

    标签: bash shell ubuntu counter


    【解决方案1】:

    romaric crailox's helpful answer 包含许多有用的指针,但可以将代码精简为更惯用的(Bash)解决方案:

    #!/bin/bash
    
    # Create the counter file on demand.
    [[ -f counter ]] || echo 0 > counter
    
    # Prompt until valid input is received.
    while read -p 'In or out? ' input; do
    
      case $input in
        'in')
          # Update the counter file by incrementing the number it contains.
          perl -i -ple '++$_' counter
          break # valid input received, exit the loop
          ;;
        'out')
          # Update the counter file by decrementing the number it contains.
          perl -i -ple '--$_' counter
          break # valid input received, exit the loop
          ;;
        *)
          echo "Invalid input." >&2  # echo error to *stderr*
          # Stay in the loop to prompt again.
          ;;    
      esac
    
    done
    
    # Read the updated counter file and echo the implied status.
    counter=$(< counter)
    if (( counter >= 1 )); then
      echo 'Logged in.'
    elif (( counter == 0 )); then
      echo 'Not logged in.'
    else
      echo "Invalid state: counter is $counter" >&2
    fi
    

    注意:

    • 使用case ... esacif ... elif ... fi 语句更简洁地处理多个条件。

    • 使用&gt;&amp;2将错误消息输出到stderr

    • 使用perl 命令更新文件counter

      • -i 激活就地更新
      • -ple 自动 prints(修改后的)输入行,-l 添加智能换行处理,-e 指定要运行的 expression(脚本)(以下参数)
      • ++$_ / --$_ 然后简单地增加/减少手头的输入行($_),感谢-p,自动获取输出,感谢-i,写回原始文件(松散地说;会创建一个新文件来替换原来的文件)。
    • 使用算术评估 ((( ... ))) 来测试数字。

    【讨论】:

    • 感谢这个更好的解决方案
    【解决方案2】:

    第一个问题是读取命令的使用。试试这个

    read -p "in or out ?" input
    
    • -p 选项是指定要打印到标准输出的内容
    • input 是用于存储用户输入的 shell 脚本变量的名称

    在此命令之后,输入变量将为inout。 然后您可以使用if 表达式测试输入是in 还是out

    if [ "$input" == "in" ] [...]
    

    要在计数器文件中添加或减去 1,您可以在文件中检索当前值,添加或减去 1 并在文件中写入新值(我不确定您是否要写入新值。试试这个:

    crt_val=$(cat ./counter)
    new_val=$(( crt_val + 1 ))
    echo $new_val > ./counter
    

    计数器文件必须存在,所以你可以在脚本的开头添加,

    if [ -e ./counter ] ; then echo "0" > ./counter ; fi
    

    最后,代码可以是这样的:

    # user entry
    read -p "in or out ? " input
    
    # initialize counter file
    if [ ! -e ./counter ] ; then echo "0" > ./counter ; fi
    
    # Doing what user entry ask to do
    if [ "$input" == "in" ]
    then
      echo "in"
      crt_val=$(cat ./counter)
      new_val=$(( crt_val + 1 ))
      echo $new_val > ./counter
    elif [ "$input" == "out" ]
    then
      echo "out"
      crt_val=$(cat ./counter)
      new_val=$(( crt_val - 1 ))
      echo $new_val > ./counter
    else
      echo "Wrong input, try in or out"
      exit 1
    fi
    
    # Output
    if [ $new_val -ge 1 ]
    then
      echo "Logged in"
    elif [ $new_val -eq 0 ]
    then
      echo "Not logged in"
    else
      echo "Wrong counter value"
    fi
    

    请注意,用户输入必须完全是 inout(区分大小写),并且不能为空。为了保护空答案,请尝试if [ "x$input" == "xin" ] [...]

    希望有帮助

    【讨论】:

      【解决方案3】:
      #!/bin/bash
      
      
      echo "In or out?"
      
      read c <&0  # reads from stdin file descriptor &0 is stdin
      
      if [[ $c == 'In' ]] || [[ $c == 'in' ]];  
      then
      counter=$(<counter.txt) # reads counter from file
      let "counter = counter +1"  # increases variable
      echo "$counter" > 'counter.txt' # write new value to file overwriting the old
      elif [[ $c == 'Out' ]] || [[ $c == 'out' ]];
      then
      counter=$(<counter.txt) # reads from file
      let "counter = counter -1"
      #echo "$counter" > 'counter.txt'
      else
      echo "wrong input..."
      fi
      

      Write to file, but overwrite it if it exists

      https://askubuntu.com/questions/385528/how-to-increment-a-variable-in-bash/706683

      http://ryanstutorials.net/bash-scripting-tutorial/bash-if-statements.php

      【讨论】:

      • 这并不可靠,因为您有竞争条件。您需要在更新期间锁定计数器文件。
      • 你能解释一下吗?
      • 您读取了计数器文件,然后您编写了更新后的计数器文件。如果第二个进程同时运行此脚本,它可能会在您的阅读和写作之间读取计数器文件,因此还看不到您的更新值。
      • 当我有空闲时间时,我将添加一个使用flock 实用程序(linux.die.net/man/1/flockstackoverflow.com/questions/22506857/locking-files-in-bash)锁定文件的版本,如果需要,您可以编辑答案...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-23
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多