我制作了一个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
变量只是一个整数,因此文本文件感觉有点过分。
答案 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...
)。多次运行脚本以查看 KEY1
和 KEY2
的输出有何不同。
注意2:在这个例子中,值是数字,如果你需要存储字符串,那么在 CREATE TABLE
而不是 NUMERIC
中使用 TEXT
。
答案 4 :(得分:0)
要在运行之间存储多个变量,我考虑的解决方案是将它们以my_var=my_value
格式保存在单独的文件中。
然后,我包含两个函数来设置和检索变量
让我们将此文件称为 context.dat
# Here I store the variables and their values
my_var_x=1
my_var_y=boo
my_var_z=0
让我们调用文件 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