Ansible读取带BOM的UTF-8 CSV时提示'dict object'无'Username'属性
解决Ansible read_csv读取带UTF-8 BOM的CSV时字段找不到的问题
问题场景
用Ansible的community.general.read_csv模块读取带UTF-8字节顺序标记(BOM)的用户列表CSV,在远程主机创建本地用户。CSV表头明确包含Username,但执行Playbook时始终报错'dict object' has no attribute 'Username'——哪怕用-vvvv模式查看输出,显示read_csv已经读取到包含Username的数据,错误依然存在。试过更换目标主机、重建文件、简化数据、调整循环逻辑、精简角色任务等方法,都没解决,最后定位到问题根源是CSV文件的UTF-8 BOM标识,换成无BOM的ASCII格式文件后就能正常运行。
有问题的CSV文件
Username,UID user1,70001
(注:该文件实际为UTF-8 with BOM编码,开头包含隐藏的BOM字符)
用到的Playbook
--- - name: Reading users from CSV file community.general.read_csv: path: files/users.csv register: users delegate_to: localhost - name: Create from CSV file user: name: "{{ item.Username }}" uid: "{{ item.UID }}" state: present loop: "{{ users.list }}"
报错信息
TASK [manage_local_users : Create from CSV file] ****************************************************************************************************************************************************************************** task path: /local/ansible/manage-users/playbooks/roles/manage_local_users/tasks/config.yml:12 fatal: [myhost.acme.com]: FAILED! => { "msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'Username' The error appears to be in '/local/ansible/manage-users/playbooks/roles/manage_local_users/tasks/config.yml': line 12, column 3, but maybe elsewhere in the file depending on the exact syntax problem. The offending line appears to be: - name: Create from CSV file ^ here" }
问题原因
UTF-8 BOM是文件开头的隐藏特殊字符(\ufeff),read_csv模块读取时会把这个字符包含在表头字段名里,导致实际的字段名变成了\ufeffUsername——而不是我们看到的Username。所以当Playbook里调用item.Username时,自然找不到对应的属性。
解决方案
方案1:直接移除CSV文件的BOM
用文本编辑器将CSV文件转成无BOM的UTF-8编码:
- VS Code:点击右下角的编码标识,选择「通过编码保存」,再选「UTF-8」(不要选「UTF-8 with BOM」)
- Notepad++:顶部菜单「编码」→「转为UTF-8无BOM格式」
- 命令行(Linux/macOS):用
sed移除BOM:sed -i '1s/^\xef\xbb\xbf//' files/users.csv
方案2:在Ansible中动态处理BOM
如果无法修改源CSV文件,可以在读取数据后,通过set_fact过滤掉字段名里的BOM字符:
- name: 读取带BOM的CSV文件 community.general.read_csv: path: files/users.csv register: users_raw delegate_to: localhost - name: 清理字段名中的BOM字符 set_fact: users: >- {% set cleaned_list = [] %} {% for user in users_raw.list %} {% set cleaned_user = {} %} {% for key, val in user.items() %} {% set cleaned_key = key | replace('\ufeff', '') %} {% set _ = cleaned_user.update({cleaned_key: val}) %} {% endfor %} {% set _ = cleaned_list.append(cleaned_user) %} {% endfor %} {{ cleaned_list }} - name: 创建本地用户 user: name: "{{ item.Username }}" uid: "{{ item.UID }}" state: present loop: "{{ users }}"
内容的提问来源于stack exchange,提问作者norinori
相关产品推荐
相关产品推荐

