web-dev-qa-db-fra.com

Comment éviter la substitution de commande bash pour supprimer le caractère de nouvelle ligne?

Pour accélérer l'exécution de scripts bash, j'aimerais conserver le résultat d'une commande dans une variable utilisant la substitution de commande, mais cette substitution remplace le caractère de début de ligne 0x0A par un espace. Par exemple:

a=`df -H`

ou

a=$( df -H )

Lorsque je veux traiter davantage $a, les caractères de nouvelle ligne sont remplacés par un espace et toutes les lignes sont maintenant sur une ligne, ce qui est beaucoup plus difficile à grep:

echo $a

Quels seraient les trucs faciles pour éviter que le caractère de nouvelle ligne ne soit supprimé par la substitution de commande?

61
Laurent

Les nouvelles lignes non suivies ne sont pas supprimées

Les nouvelles lignes que vous recherchez sont là, vous ne les voyez pas, car vous utilisez echo sans citer la variable. 

Validation:

$ a=$( df -H )
$ echo $a
Filesystem Size Used Avail Use% Mounted on /dev/sda3 276G 50G 213G 19% / udev 2.1G 4.1k 2.1G 1% /dev tmpfs 832M 820k 832M 1% /run none 5.3M 0 5.3M 0% /run/lock none 2.1G 320k 2.1G 1% /run/shm
$ echo "$a"
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       276G   50G  213G  19% /
udev            2.1G  4.1k  2.1G   1% /dev
tmpfs           832M  820k  832M   1% /run
none            5.3M     0  5.3M   0% /run/lock
none            2.1G  320k  2.1G   1% /run/shm
$ 

Trailing les nouvelles lignes sont supprimées

Comme @ user4815162342 l'a correctement souligné, bien que les nouvelles lignes de la sortie ne soient pas supprimées, nouvelles lignes suivies sont supprimées avec substitution de commande. Voir l'expérience ci-dessous:

$ a=$'test\n\n'
$ echo "$a"
test


$ b=$(echo "$a")
$ echo "$b"
test
$

Dans la plupart des cas, cela n'a pas d'importance, car echo ajoutera la nouvelle ligne supprimée (sauf si elle est invoquée avec l'option -n). Cependant, dans certains cas Edge, la sortie d'un programme contient plus d'une nouvelle ligne, significatif pour une raison quelconque. 

Solutions de contournement

1. Ajouter un personnage factice

Dans ce cas, comme indiqué par @Scrutinizer, vous pouvez utiliser la solution de contournement suivante:

$ a=$(printf 'test\n\n'; printf x); a=${a%x}
$ echo "$a"
test


$ 

Explication: _ Le caractère x est ajouté à la sortie (à l'aide de printf x), après les nouvelles lignes. Comme les nouvelles lignes ne sont plus fin, elles ne sont pas supprimées par la substitution de commande. L'étape suivante consiste à supprimer le x que nous avons ajouté à l'aide de l'opérateur % dans ${a%x}. Maintenant nous avons la sortie originale, avec toutes les nouvelles lignes présentes !!!

2. Lire en utilisant la substitution de processus

Au lieu d'utiliser la substitution de commande pour affecter la sortie d'un programme à une variable, nous pouvons utiliser plutôt substitution de processus pour alimenter la sortie du programme avec la commande intégrée read (crédit de @ormaaj). La substitution de processus préserve toutes les nouvelles lignes. Lire le résultat sur une variable est un peu délicat, mais vous pouvez le faire comme ceci:

$ IFS= read -rd '' var < <( printf 'test\n\n' ) 
$ echo "$var"
test


$ 

Explication:

  • Nous définissons le séparateur de champ interne} _ pour la commande de lecture sur null, avec IFS=. Sinon, read n'affecterait pas la sortie entière à var, mais uniquement le premier jeton.
  • Nous appelons read avec les options -rd ''. r permet d'éviter que la barre oblique inversée agisse comme un caractère spécial. Avec d '', définissez le délimiteur sur néant de sorte que la lecture soit lue dans son intégralité au lieu de la première ligne.

3. Lire d'un tuyau

Au lieu d'utiliser une substitution de commande ou de processus pour affecter la sortie d'un programme à une variable, nous pouvons diriger la sortie du programme vers la commande read (crédit de @ormaaj). La tuyauterie préserve également toutes les nouvelles lignes. Notez toutefois que cette fois-ci, nous définissons le comportement optionnel du shell lastpipe en utilisant le __ intégré shopt . Cela est nécessaire pour que la commande read soit exécutée dans l'environnement Shell actuel. Sinon, la variable sera affectée dans un sous-shell et ne sera pas accessible à partir du reste du script.

$ cat test.sh 
#!/bin/bash
shopt -s lastpipe
printf "test\n\n" | IFS= read -rd '' var
echo "$var"
$ ./test.sh 
test


$
97
user000001

J'essayais de comprendre cela parce que j'utilisais bash pour diffuser le résultat de l'exécution de l'interpréteur sur un script F #. Après quelques essais et erreurs, nous avons résolu le problème:

$ cat fsi.ch
#!/bin/bash
echo "$(fsharpi --quiet --exec --nologo $1)"

$ fsi.ch messages.fsx
Welcome to my program. Choose from the menu:
new | show | remove

En supposant, bien sûr, que vous ayez besoin de lancer un programme terminal . J'espère que cela vous aidera.

0
Alexander