Impossible d'parsingr la sortie séparée par espace de awk

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