bash-在运行之间存储变量的更好方法?

时间:2012-09-08 21:07:08

标签: bash variables text storage

我制作了一个bash脚本,我每小时用crontab运行一次,我需要存储一个变量,以便下次运行时可以访问它。该脚本每次运行时都会更改变量,因此我无法对其进行硬编码。现在我将其写入txt文件,然后将其读回。有没有比这更好的方法呢?我正在阅读txt文件的方式是我在这里找到的,我不明白它,它有点笨重。是否没有内置命令?无论如何,这是适用的代码,更改了一些变量以使其更容易阅读。

while read x; do
  var=$x
done < var.txt

# Do some stuff, change var to a new value

echo $var > var.txt

变量只是一个整数,因此文本文件感觉有点过分。

7 个答案:

答案 0 :(得分:9)

无需使用var; x将在当前shell的范围内。或者,

read var < var.txt
# do stuff with var
echo $var > var.txt

我建议使用简单的文本文件来存储变量。但是,自修改脚本存在(高度可疑)选项。 仅供娱乐使用!

#!/bin/bash

read val < <( tail -n 1 "$0" )

(( val++ ))
echo "$val"

tmp=$(mktemp /tmp/XXXXXXX)
sed '$s/.*/'$val'/' "$0" > "$tmp"
mv "$tmp" "$0"

exit
0

关键是将倒数第二行作为退出命令,因此不会执行任何操作。最后一行是您要保留的变量值。当脚本运行时,它read来自它自己的最后一行。在退出之前,它使用sed将自身的副本写入临时文件,最后一行使用持久值的当前值进行修改。然后我们用temp文件覆盖当前脚本(假设我们有权这样做)。

但是说真的吗?不要这样做。

答案 1 :(得分:5)

我知道这是一个老问题。但是,我仍然决定在这里发布我的解决方案,希望对于那些来到这里寻找在会话之间序列化env变种的方法的人来说可能会有所帮助。

简单的方法就是将“var_name = var_value”写入文件,例如“./environ”。然后在以下会话中“source ./envrion”。例如:

echo "var1=$var1" > ./environ

保持变量所有属性的更全面(和优雅?)方式是使用“declare -p”:

declare -p var1 var2 > ./environ
# NOTE: no '$' before var1, var2

稍后,在“source ./envrion”之后,您可以获得var1 var2,除了其值之外还恢复了所有属性。这意味着它可以处理数组,整数等。

对于“declare -p xx”的一个警告,但是:如果将“source ./environ”包装到函数中,那么所有源变量在函数中都是可见的,因为默认情况下“declare”将变量声明为local那些。为了避免这种情况,您可以从任何函数(或“主”函数)中“获取”或修改./environ以在声明后添加“-g”(这使得相应的变量为全局)。例如:

sed -i 's/^declare\( -g\)*/declare -g/' ./environ
# "\( -g\)?" ensure no duplication of "-g"

答案 2 :(得分:1)

1-您可以简化脚本,因为您只有一个变量

var=`cat var.txt`
# Do some stuff, change var to a new value   
echo $var > var.txt

2-您可以将变量存储在环境中:

export var

# Do some stuff, change var to a new value

但是你需要提示它. script.ksh(在开始时点)。但它不应该“退出”,我不确定这会在cron中起作用......

答案 3 :(得分:1)

根据您的用例,这可能有点矫枉过正,但如果您需要存储和跟踪多个变量(或来自多个脚本),请考虑使用具有命令行界面({{3} }),并且通常在 linux/macos 系统上预装 ootb。

DB='storage.db'

KEY1='eurusd'
VAL1=1.19011

KEY2='gbpeur'
VAL2=1.16829

# create table if not present (ONLY NEEDS TO BE RUN ONCE)
QUERY_CREATE="CREATE TABLE IF NOT EXISTS records (id INTEGER PRIMARY KEY, name TEXT NOT NULL, value NUMERIC NOT NULL);"
sqlite3 "$DB" "$QUERY_CREATE"

# write a key-value pair to database (creates a new row each time)
QUERY_INSERT="INSERT INTO records(name, value) VALUES ('${KEY1}', '${VAL1}');"
sqlite3 "$DB" "$QUERY_INSERT"

# write a key-value pair to database (REPLACE previous value!)
# using 42 as a hard-coded row ID
QUERY_REPLACE="REPLACE INTO records(id, name, value) VALUES (42, '${KEY2}', '${VAL2}');"
sqlite3 "$DB" "$QUERY_REPLACE"

# read value from database
QUERY_SELECT1="SELECT value FROM records WHERE name='${KEY1}';"
QUERY_SELECT2="SELECT value FROM records WHERE name='${KEY2}';"

echo "***** $KEY1 *****"
# store db value in a variable
db_value1=$(sqlite3 "$DB" "$QUERY_SELECT1")
echo $db_value1
## OUTPUT: 1.19011

echo "***** $KEY2 *****"
db_value2=$(sqlite3 "$DB" "$QUERY_SELECT2")
echo $db_value2
## OUTPUT: 1.16829
<块引用>

注意:如果您没有明确传递行 ID,那么每次脚本调用时都会添加一个新行。要始终更新到同一行,请使用带有显式 ID 的 REPLACE INTO(例如,在 42 语句中可以看到的 REPLACE INTO...)。多次运行脚本以查看 KEY1KEY2 的输出有何不同。


<块引用>

注意2:在这个例子中,值是数字,如果你需要存储字符串,那么在 CREATE TABLE 而不是 NUMERIC 中使用 TEXT

答案 4 :(得分:0)

要在运行之间存储多个变量,我考虑的解决方案是将它们以my_var=my_value格式保存在单独的文件中。

然后,我包含两个函数来设置和检索变量

  1. 在存储变量及其值的文件中:
  2. 让我们将此文件称为 context.dat

    # Here I store the variables and their values
    my_var_x=1
    my_var_y=boo
    my_var_z=0
    
    1. 在实际脚本中:
    2. 让我们调用文件 multiple_run.sh

      context=./context.dat
      
      function update_variables(){
          # update the variable context
          source $context
      }
      
      function set_variable(){
          # store variable
          variable=$1 #variable to be set
          value=$2    # value to give to the value
          # modify the file storing the value
          sed -i 's/'${variable}'.*/'${variable}'='${value}'/' $context
      }
      
      ##################
      # Test code
      echo var_x
      update_variables
      echo var_x
      # do something
      set_variable var_x 2
      echo $var_x
      

      这是其中一种方法。使用这种方法,您需要先创建存储文件,然后为每个变量创建每一行。此外,context.dat是任何其他脚本都可以访问的先验。

答案 5 :(得分:0)

刚刚发现了这个伟大的简单项目(重写的fork)。一个简单而强大的键/值对存储bash。看起来很完美。在后台,每个数据库都是一个目录,每个键都是一个文件,而值都在文件中。

https://github.com/imyller/kv-sh

  • 微小的键值数据库
  • 可配置的数据库目录(默认:sql = "INSERT INTO customers (name, address) VALUES (%s, %s)" val = ("John", "Highway 21") mycursor.execute(sql, val) mydb.commit()
  • 通过~/.kv-sh导入函数使用
  • 完整的数据库转储/还原
  • 支持辅助只读默认数据库
$ . ./kv-sh

默认数据库

. ./kv-sh # import kv-sh functions (use default database directory; see configuration environment variables for available options) kvset <key> <value> # assign value to key kvget <key> # get value of key kvdel <key> # delete key kvexists <key> # check if key exists kvkeys {-l|-d|-a} # list all keys (-l local only, -d default only, -a all (default)) kvlist {-a} # list all key/value pairs (-a all keys, including default) kvdump {-a} # database dump (-a all keys, including default) kvimport # database import (overwrite) kvrestore # database restore (clear and restore) kvclear # clear database 支持辅助只读默认数据库。如果启用,则如果未指定本地值,则从默认值数据库返回键-值对。

通过设置kv-sh启用默认数据库:

DB_DEFAULTS_DIR

答案 6 :(得分:-1)

我最终做了以下事情。更喜欢一个文件中的变量,但这稍微膨胀了代码。这个阅读的东西怎么样?您可以将多个变量存储在单独的文件中,比如variables.txt,然后将主程序放在main.sh中。编写单独的脚本来加载和保存变量可能会更好。

对于varibles.txt:

A=0
B=0
C=0

对于main.sh:

#!/bin/bash

#reload variables
A=`cat ./variables.txt|grep "A="|cut -d"=" -f2`
B=`cat ./variables.txt|grep "B="|cut -d"=" -f2`
C=`cat ./variables.txt|grep "C="|cut -d"=" -f2`

#print variables
printf "$A\n"
printf "$B\n"
printf "$C\n"

#update variables
A=$((($A+1)))
B=$((($B+2)))
C=$((($C+3)))

#save variables to file
#for A
 #remove entry for A
 cat ./variables.txt|grep -v "A=">>./tmp.txt
 #save entry for A
 printf "A=$A\n">>./tmp.txt
 #move tmp.txt to variables.txt
mv ./tmp.txt ./variables.txt

#for B
 #remove entry for B
 cat ./variables.txt|grep -v "B=">>./tmp.txt
 #save entry for B
 printf "B=$B\n">>./tmp.txt
 #move tmp.txt to variables.txt
 mv ./tmp.txt ./variables.txt

#for C
 #remove entry for C
 cat ./variables.txt|grep -v "C=">>./tmp.txt
 #save entry for C
 printf "C=$C\n">>./tmp.txt
 #move tmp.txt to variables.txt
 mv ./tmp.txt ./variables.txt