![无法解析 awk 的空格分隔输出](https://linux22.com/image/117497/%E6%97%A0%E6%B3%95%E8%A7%A3%E6%9E%90%20awk%20%E7%9A%84%E7%A9%BA%E6%A0%BC%E5%88%86%E9%9A%94%E8%BE%93%E5%87%BA.png)
如果我理解正确的话,输出的默认分隔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
为什么我不能像我预期的那样解析awk
with的输出?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