适用于Ansible的Linux命令:获取用户及其所属组并生成指定输出
Solution 1: Modified Bash Command (Escaped for Ansible)
Here's the updated single-line command that appends group information, with all quotes properly escaped to work in Ansible's shell or command module:
cat /etc/passwd | xargs -n1 -I{} bash -c 'a=$(echo "{}" | cut -f1 -d:); echo -e "\n$a"; chage -l "$a"; echo -e "Linux shell\t: $(echo "{}" | cut -f7 -d:)"; echo -e "Groups\t: $(groups "$a" | cut -d: -f2 | sed '\''s/^ //; s/ /, /g'\'')"' >> users-list.log
Key Changes:
- Added a line to fetch and format groups:
groups "$a"gets all groups for the user,cutremoves the username prefix, andsedcleans up spacing to separate groups with commas. - Escaped single quotes in the
sedcommand using\'\'to avoid breaking the outer single-quotedbash -cstring (critical for Ansible compatibility). - Switched from backticks to
$()for command substitution to improve readability and avoid nested quote conflicts. - Added quotes around
$ato handle edge cases with usernames containing spaces (though uncommon).
Solution 2: Ansible-Native Playbook (Recommended)
For a more maintainable, idempotent approach that leverages Ansible's built-in modules instead of raw bash, use this playbook. It gathers user, shadow, and group data natively and templates the output to your log file:
- name: Collect detailed user information hosts: your_target_hosts tasks: - name: Gather passwd, shadow, and group data getent: database: "{{ item }}" loop: - passwd - shadow - group - name: Generate formatted user info log copy: dest: /users-list.log content: | {% for username in getent_passwd %} {{ username[0] }} {% set shadow = getent_shadow[username[0]] %} Last password change : {% if shadow[2] == '0' %}never{% else %}{{ (shadow[2] | int * 86400) | strftime('%b %d, %Y') }}{% endif %} Password expires : {% set max_days = shadow[4] | int %}{% if max_days == 99999 %}never{% else %}{{ (shadow[2] | int + max_days) * 86400 | strftime('%b %d, %Y') }}{% endif %} Password inactive : {% set inactive_days = shadow[6] | int %}{% if inactive_days == -1 %}never{% else %}{{ (shadow[2] | int + shadow[4] | int + inactive_days) * 86400 | strftime('%b %d, %Y') }}{% endif %} Account expires : {% set expire_date = shadow[7] | int %}{% if expire_date == -1 %}never{% else %}{{ expire_date * 86400 | strftime('%b %d, %Y') }}{% endif %} Minimum number of days between password change : {{ shadow[3] }} Maximum number of days between password change : {{ shadow[4] }} Number of days of warning before password expires : {{ shadow[5] }} Linux shell : {{ username[6] }} Groups : {{ getent_group | selectattr('1', 'contains', username[0]) | map(attribute='0') | join(', ') }} {% endfor %} force: yes
Why This Is Better:
- No dependency on external bash commands (uses Ansible's built-in
getentmodule which works across most Unix-like systems). - Idempotent: Running the playbook multiple times won't append duplicate entries to the log (the
copymodule replaces the file each time). - Easier to modify or extend (e.g., add more user attributes) without dealing with complex bash string escaping.
内容的提问来源于stack exchange,提问作者Romain
相关产品推荐
相关产品推荐

