Bash - 遍历 SQLite3 数据库

Bash - Iterate trough SQLite3 DB

快速概览:我得到了包含以下结构和数据的 sqlite3 数据库

ID|名称|值
1|SomeName1|SomeValue1
2|SomeName2|SomeValue2
3|SomeName3|SomeValue3
(此处 SomeValue3 的延续,在 ENTER 之后)

问题出在“值”列的迭代中,我正在使用该代码:

records=(`sqlite3 database.db "SELECT Value FROM Values"`)

for record in "${records[@]}"; do
   echo $record
done

问题是应该有三个值使用该迭代,但它显示了四个。 结果我收到了:

1 step of loop - SomeValue1
2 step of loop - SomeValue2
3 step of loop - SomeValue3
4 step of loop - (continuation of SomeValue3 in here, after ENTER)

它应该在第三步结束,只显示类似这样的换行符:

3 step of loop - SomeValue3
(continuation of SomeValue3 in here, after ENTER)

有什么建议可以用 bash 处理吗?
提前致谢!

您的问题是 Bash 中的 IFS(内部字段分隔符),for 循环将其视为新记录。

您最好的选择是从 sqlite 中删除 select 语句中的换行符,例如:

records=(`sqlite3 database.db "SELECT replace(Value, '\n', '') FROM Values"`)

for record in "${records[@]}"; do
   echo $record
done

或者,您 可以 更改 Bash 中的 IFS - 但您依赖换行符作为记录之间的分隔符。

与其依靠分词来用命令的结果填充数组,不如使用内置的 readarray 或通过循环一次读取结果更可靠。两者的示例如下,使用 sqlite3ascii 输出模式,其中行由字节 0x1E 分隔,行中的列由 0x1F 分隔。这样可以轻松接受数据中的文字换行符。

#!/usr/bin/env bash

# The -d argument to readarray and read changes the end-of-line character
# from newline to, in this case, ASCII Record Separator

# Uses the `%q` format specifier to avoid printing the newline
# literally for demonstration purposes.

echo "Example 1"
readarray -d $'\x1E' -t rows < <(sqlite3 -batch -noheader -ascii database.db 'SELECT value FROM "Values"')
for row in "${rows[@]}"; do
    printf "Value: %q\n" "$row"
done

echo "Example 2 - multiple columns"
while IFS=$'\x1F' read -d $'\x1E' -ra row; do
    printf "Rowid: %d Value: %q\n" "${row[0]}" "${row[1]}"
done < <(sqlite3 -batch -noheader -ascii database.db 'SELECT rowid, value FROM "Values"')

产出

Example 1
Value: SomeValue1
Value: SomeValue2
Value: $'SomeValue2\nand more'
Example 2 - multiple columns
Rowid: 1 Value: SomeValue1
Rowid: 2 Value: SomeValue2
Rowid: 3 Value: $'SomeValue2\nand more'

  1. 请参阅 Don't Read Lines With for 以详细了解为什么您的方法不好。
  2. 由于 VALUES 是一个 SQL 关键字,当将它用作 table 名称时(不要那样做!)它必须用双引号转义。