我是 shell 脚本世界的新手,对 shell 脚本没有太多了解。我的工作要求我编写一个脚本,从存储在 CSV 文件中的记录列表中获取电话号码。
对于每个电话号码,它会在数据库中的用户表中进行搜索,如果找到匹配项,则会通过在电话号码前面添加“A2B1”来更新电话号码列。
例如,如果在包含记录的 csv 文件中找到数据库中类似“456789”的电话号码记录,则电话号码列将更新为“A2B1 456789”。
我想到了以下方法:首先,我将使用“cut”命令从 CSV 文件的每一行中取出第二列。 (但是,我不知道如何将每行第二列的值存储在变量中,以便我可以在SQL查询语句中使用它。)创建一个数据库链接,并编写SQL搜索语句/查询。
然后如果返回一些记录,那么就会完成上面提到的更新。
我不知道如何执行此操作或用 shell 语言编写它。我尝试考虑一种方法将查询的输出传送到文件并检查文件大小是否为零,如果不是,则采用文件中的变量(这是查询返回的记录/电话号码),然后将其存储在变量中并执行更新操作,但我怀疑这是否是一个好方法,而且考虑到我在这个领域的两天婴儿期,我对此没有信心语法也是。热切等待您的帮助
答案1
当你能在 shell 脚本中执行查询/更新/等操作,使用对数据库和 CSV 文件都有良好支持的语言(如或)mysql
要容易得多。perl
python
这是在 中perl
使用 perlDBI
模块以及DBD::CSV
和DBD::mysql
模块执行此操作的一种方法。
它从 CSV 文件中读取每一行(我将其称为“updates.csv”并假设列名称为),并对mysql 中的数据库表phonenum
发出 SQLUPDATE
命令。更改以适合您的数据库。users
dbname
dbname
注意:以下代码未经测试,但应该可以工作。由于它未经测试,我可能犯了一些拼写错误或其他错误。
我强烈地建议先在复制数据库而不是立即在真实数据上运行它。事实上,它是总是在真实数据的副本上测试代码是个好主意,无论您正在编写什么或使用什么语言编写代码。
#! /usr/bin/perl
use strict;
use DBI;
###
### variables setup
###
# DBD::CSV treats all .csv files in this dir as tables.
# i.e. this directory is the "database" and the .csv files
# are the tables in that database.
my $csv_dir = '/path/to/csv/dir';
my $csv_db = 'updates'; # corresponds to "$csv_dir/updates.csv"
my $m_db = 'dbname'; # replace with your mysql database name
my $m_user = 'username';
my $m_pass = 'password';
my $m_host = 'localhost';
my $m_port = '3306';
my $m_dsn = "DBI:mysql:database=${m_db};host=${m_host};port=${m_port}";
###
### database handle setup
###
# database handle for CSV connection
my $c_h = DBI->connect ("DBI:CSV:", undef, undef, {
f_ext => ".csv/r",
f_dir => $csv_dir,
RaiseError => 1,
}) or die "Cannot connect: $DBI::errstr";
# database handle for mysql connection
my $m_h = DBI->connect($m_dsn, $m_user, $m_pass, { PrintError => 0 });
###
### all set up, time to do some work.
###
# NOTE: this script assumes that the .csv file contains a header line with
# the field names as the first line of the file.
#
# If not, the easiest thing to do is edit it with your preferred text
# editor and add one. Otherwise, see `man DBD::CSV` to find out how to
# specify field names.
#
# or EDIT and uncomment the following three lines of code:
#$c_h->{csv_tables}{$csv_db} = {
# col_names => [ qw(column1 phonenum column3 column4 ...) ];
#};
# prepare statement handle for csv db query using a placeholder ? for the
# column name.
my $c_sth = $c_h->prepare("select phonenum from ?");
# and execute it. later, we'll use a forech loop to read the data returned
$c_sth->execute($csv_db);
# prepare the SQL statement for the mysql db using placeholders ? for
# the values. this assumes that the column/field name is also called
# 'phonenum' in mysql. These placeholders are invaluable, they automaticaly
# quote any data that needs to be quoted (e.g. strings) while not quoting
# things that shouldn't be quoted (e.g. integers). They prevent a huge
# range of common mistakes.
#
# prepare it once, execute it multiple times with different values.
my $m_sth = $m_h->prepare('UPDATE users SET phonenum = ? WHERE phonenum = ?');
$m_h->begin_work; # begin transaction
foreach ($c_sth->fetchrow_array) {
chomp;
my $newphone = "A2B1 $_";
$m_sth = $m_sth->execute($newphone, $_);
};
$m_h->commit; # commit transaction
###
### we're done. finish the statement handles and disconnect from
### the databases.
###
$c_sth->finish;
$m_sth->finish;
$c_h->disconnect;
$m_h->disconnect;
它看起来比一般的快速 shell 脚本更长,但大部分代码只是变量和数据库句柄设置(并且该设置代码可以在其他类似的脚本中重复使用)。完成这项工作的实际代码(不包括注释)只有大约六行左右。
答案2
您可以使用这个脚本:
#!/bin/bash
PREFIX="A2B1 "
TABLE="sqltablename"
COLUMN="sqlcolumnname"
if [[ ! -r "$1" ]]; then
echo "unable to read file '$1'"
exit 1
fi
cut -d, -f2 "$1" | while read phonenum; do
newnum="$PREFIX $phonenum"
echo "UPDATE $TABLE SET $COLUMN = '$newnum' WHERE $COLUMN = '$phonenum';"
done
如果您使用 CSV 文件作为参数(例如./script.sh /path/to/mydata.csv
)运行它,这将输出一系列 SQL 语句,这些语句将按照您的描述更新数据。修改脚本以使用正确的表和列名称。
一旦您确认它为您提供了您想要的语句,您就可以将其通过管道传输到您选择的 SQL 引擎中,或者将输出保存到一个 SQL 文件中,您可以按照您喜欢的方式执行该文件./script.sh /path/to/mydata.csv > /path/to/updatephonenumbers.sql
。