无法解析 awk 的空格分隔输出

无法解析 awk 的空格分隔输出

如果我理解正确的话,输出的默认分隔awk符是空间

但是,以下脚本的行为并不符合我的预期。我无法将 的输出解析awk为数组:

#!/bin/bash
echo "------ with input string from awk ------"
ALL_TTY_OWNERS_STR=$(ls -l /dev | grep tty | awk '{print $3}')

read -r -a ALL_TTY_OWNERS_ARRAY <<< "$ALL_TTY_OWNERS_STR"

echo "${#ALL_TTY_OWNERS_ARRAY[@]}" # This says 1
echo "${ALL_TTY_OWNERS_ARRAY[0]}" # "root", as expected
echo "${ALL_TTY_OWNERS_ARRAY[1]}" # empty string, expected "root"
echo "${ALL_TTY_OWNERS_ARRAY[2]}" # empty string, expected "root"


echo "------ with my manually created input string ------"
ALL_TTY_OWNERS_STR="root root root" # only for testing

read -r -a ALL_TTY_OWNERS_ARRAY <<< "$ALL_TTY_OWNERS_STR"

echo "${#ALL_TTY_OWNERS_ARRAY[@]}" # 3, as expected
echo "${ALL_TTY_OWNERS_ARRAY[0]}" # "root", as expected
echo "${ALL_TTY_OWNERS_ARRAY[1]}" # "root", as expected
echo "${ALL_TTY_OWNERS_ARRAY[2]}" # "root", as expected

为什么我不能像我预期的那样解析awkwith的输出?read

答案1

是关于场地分隔器。

你需要定义记录分隔符将每个字符串放在单个字符串中。使用ORS参数:

ls -l /dev | grep tty | awk 'BEGIN { ORS=" " }; {print $3}'

没有它你的输出将:

root
root
root
etc...

当你定义ALL_TTY_OWNERS_STR变量时只放在第一位数组第一个元素中的输出字符串。因此,您的数组将仅包含一个元素,这正是您所得到的

答案2

输出的默认字段分隔符是空格。但记录分隔符是一个新行。ALL_TTY_OWNERS_STR包含一堆root由换行符分隔的 s:

$ printf "%q\n" "$ALL_TTY_OWNERS_STR"
$'root\nroot\nroot\n....

默认情况下read会读取到第一个换行符。

如果您只想要 中的所有用户ALL_TTY_OWNERS_ARRAY,则执行以下操作可能会更简单:

ALL_TTY_OWNERS_ARRAY=( $(stat -c '%U' /dev/*tty*) )

答案3

read -a array将一条记录中的所有单词读入array.

如果要读取整个输入中的所有单词,请使用输入中未出现的记录分隔符,例如-d ''使用 NUL 字符作为记录分隔符,或者-d ::不能出现在用户名中)。

IFS=$'\n' read -rd '' -a array < <(ls -Ll /dev | awk '/tty/{print $3}')

(这里使用-L符号链接,返回设备的所有权,而不是符号链接)。

或者用于readarray每个线要存储在数组中的输入。

readarray -t array < <(ls -Ll /dev | awk '/tty/{print $3}')

或者您可以使用 split+glob 运算符:

set -o noglob # disable glob part
IFS=$'\n'     # split on newline
array=($(ls -Ll /dev | awk '/tty/{print $3}')) # invoke split+glob by leaving
                                               # the $(...) unquoted.

请注意,tty在 的整个输出中查找ls -Ll,因此包括用户名和组名、文件名(以及符号链接的目标,如果省略-L)。如果您只想考虑文件名,您可以这样做

ls -Lld /dev/*tty* | awk '{print $3}'

反而。

有了zsh,你可以这样做:

zmodload zsh/stat
stat -s -A array +uid /dev/*tty*

(这将有利于也适用于包含空格的用户名)。

答案4

如果您不引用 after 变量<<<,则换行符将成为您期望的空白,并且结果将全部在一行上:

read -r -a ALL_TTY_OWNERS_ARRAY <<< $ALL_TTY_OWNERS_STR

相关内容