23

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

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

# Do some stuff, change var to a new value

echo $var > var.txt

变量只是一个整数,所以文本文件感觉有点过头了。

4

7 回答 7

19

没有必要使用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将自身的副本写入临时文件,最后一行修改为持久值的当前值。然后我们用临时文件覆盖当前脚本(假设我们有权限这样做)。

不过实话说?不要这样做。

于 2012-09-08T21:18:44.497 回答
6

我知道这是一个老问题。但是,我仍然决定在这里发布我的解决方案,希望它可能对来这里寻找在会话之间序列化环境变量的方法的其他人有所帮助。

简单的方法就是将“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”默认情况下将变量声明为本地变量。为了避免这种情况,您可以“源”出任何函数(或在“主”函数中)或修改 ./environ 以在声明后添加“-g”(这使相应的变量成为全局变量)。例如:

sed -i 's/^declare\( -g\)*/declare -g/' ./environ
# "\( -g\)?" ensure no duplication of "-g"
于 2015-11-18T12:42:19.643 回答
3

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 中工作......

于 2012-09-08T21:20:39.790 回答
1

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

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,则每次脚本调用都会添加一个新行。REPLACE INTO要始终使用显式 ID更新到同一行(例如42,可以在REPLACE INTO...语句中看到)。多次运行脚本以查看KEY1和的输出有何不同KEY2


注意 2:在此示例中,值是数字,如果您需要存储字符串,请使用 inCREATE TABLE而不是NUMERICuse TEXT

于 2021-03-23T11:38:25.017 回答
0

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

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

  1. 在存储变量及其值的文件中:

我们称这个文件为 context.dat

# Here I store the variables and their values
my_var_x=1
my_var_y=boo
my_var_z=0
  1. 在实际脚本中:

让我们调用文件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 是任何其他脚本都可以先验访问的。

于 2018-03-22T17:54:00.327 回答
0

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

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

  • 小型键值数据库
  • 可配置的数据库目录(默认~/.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

DB_DIR="/tmp/.kv" DB_DEFAULTS_DIR="/tmp/.kv-default" . ./kv-sh
于 2020-08-19T05:34:48.747 回答
-1

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

对于变量.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
于 2013-11-01T09:51:29.413 回答