Si je comprends bien, le séparateur par défaut pour la sortie de awk
est l' espace .
Cependant, le script suivant ne se comporte pas comme prévu. Je n'arrive pas à parsingr la sortie de awk
dans un tableau:
#!/bin/bash echo "------ with input ssortingng 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 ssortingng, expected "root" echo "${ALL_TTY_OWNERS_ARRAY[2]}" # empty ssortingng, expected "root" echo "------ with my manually created input ssortingng ------" 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
Pourquoi ne puis-je pas parsingr la sortie de awk
avec read
comme je pensais pouvoir le faire?
Il s'agit de séparateur de champs .
Vous devez définir le séparateur d' loggings pour mettre chaque string en un seul. Utilisez le ORS
:
ls -l /dev | grep tty | awk 'BEGIN { ORS=" " }; {print $3}'
Sans cela, vous produisez:
root root root etc...
Et lorsque vous définissez la variable ALL_TTY_OWNERS_STR
, vous ne placez que la première string de sortie dans le premier élément du tableau. A cause de cela, votre tableau ne contiendra qu'un seul élément et c'est exactement ce que vous obtenez
Le séparateur de champ par défaut pour la sortie est l'espace. Mais le séparateur d'logging est une nouvelle ligne. ALL_TTY_OWNERS_STR
contient un groupe de root
séparées par des nouvelles lignes:
$ printf "%q\n" "$ALL_TTY_OWNERS_STR" $'root\nroot\nroot\n....
Et read
par défaut lit jusqu'à la première nouvelle ligne.
Si vous voulez simplement que tous les users dans ALL_TTY_OWNERS_ARRAY
, il pourrait être plus simple de faire quelque chose comme:
ALL_TTY_OWNERS_ARRAY=( $(stat -c '%U' /dev/*tty*) )
read -a array
lit tous les mots d'un logging dans un array
.
Si vous voulez lire tous les mots de l'input entière, utilisez un séparateur d'loggings qui ne se trouve pas dans l'input, comme avec -d ''
qui utilise le caractère NUL comme séparateur d'logging ou -d :
(comme :
ne peut pas se produire dans un nom d'user).
IFS=$'\n' read -rd '' -a array < <(ls -Ll /dev | awk '/tty/{print $3}')
(ici en utilisant -L
sorte que pour les liens symboliques, la propriété des périphériques par opposition au lien symbolique est returnné).
Ou utilisez readarray
pour chaque ligne de l'input à stocker dans le tableau.
readarray -t array < <(ls -Ll /dev | awk '/tty/{print $3}')
Ou vous pouvez utiliser l'opérateur 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.
Notez que le tty
est recherché dans toute la sortie de ls -Ll
, incluant donc le nom de l'user et du groupe, le nom du file (et la cible du lien symbolique si vous omettez le -L
). Si vous ne souhaitez considérer que le nom du file, vous pouvez le faire
ls -Lld /dev/*tty* | awk '{print $3}'
au lieu.
Avec zsh
, vous pourriez faire:
zmodload zsh/stat stat -s -A array +uid /dev/*tty*
(qui aurait l'avantage de travailler aussi pour les noms d'user contenant des blancs).
Si vous ne citez pas la variable après <<<
, les nouvelles lignes deviendront les espaces que vous attendez et le résultat sera sur une seule ligne:
read -r -a ALL_TTY_OWNERS_ARRAY <<< $ALL_TTY_OWNERS_STR