默认情况下,Bash 在任何空白字符处拆分字符串。首先,您需要为您的输出提供一个唯一的列标识符,您可以使用mysql --batch 来获取制表符分隔的 csv 输出。
来自 MySQL 手册页:
--批处理,-B
使用制表符作为列分隔符打印结果,每行换行。使用此选项,mysql 不使用历史文件。
批处理模式导致非表格输出格式和特殊字符转义。使用 raw 模式可以禁用转义;查看 --raw 选项的描述
您希望结果被转义,所以不要使用--raw,否则结果数据中的制表符会再次打破循环。
要跳过第一行(列名),您还可以使用选项--skip-column-names
现在您可以遍历每一行并按制表符分隔它。
您只能通过临时覆盖 IFS 变量 (Internal Field Separator) 来强制 bash 按制表符拆分。
示例
# myread prevents collapsing of empty fields
myread() {
local input
IFS= read -r input || return $?
while (( $# > 1 )); do
IFS= read -r "$1" <<< "${input%%[$IFS]*}"
input="${input#*[$IFS]}"
shift
done
IFS= read -r "$1" <<< "$input"
}
# loop though the result rows
while IFS=$'\t' myread id name surname url created; do
echo "id: ${id}";
echo "name: ${name}";
echo "surname: ${surname}";
echo "url: ${url}";
echo "created: ${created}";
done < <(mysql --batch --skip-column-headers -e "SELECT id, name, surname, url, created FROM users")
myread 功能this answerStefan Kriwanekthis answer
注意:
您需要非常小心引号和变量分隔符。
如果你只是echo $row[0] 没有大括号,你会得到错误的结果
编辑
你仍然有一个问题,当一个列返回空字符串时,因为内部字段分隔符匹配任意数量的已定义字符:
row1\t\trow3 将创建一个数组 [row1,row3] 而不是 [row1,,row3]
我找到了一个非常好的方法来解决这个问题,更新了上面的例子。
另外read可以直接将输入流分离成变量。