J'essaie de stocker plusieurs lignes dans une variable bash, mais cela ne semble pas fonctionner.
Par exemple, si je liste /bin
un fichier par ligne et que je le stocke $LS
, alors je passe en $LS
tant que stdin à wc
, il renvoie toujours 1:
$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1
Si j'essaie de sortir à l'écran, j'obtiens différents résultats: echo
imprime toutes les lignes sur une seule ligne, tandis que printf
n'imprime que la première ligne:
#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS
Ainsi, une variable bash peut contenir plusieurs lignes?
printf "%s\n" $LS
feraient.wc
et d'autres commandes:wc -l <<< "$LS"
printf '%s\n' "$LS"
si vous voulez voir la nouvelle ligne. C'est mal tapé, corrigé!Les sauts de ligne sont dans la variable.
LS=$(ls -1)
définit la variableLS
sur la sortie dels -1
(qui produit la même sortie quels
, soit dit en passant, sauf lorsque la sortie est envoyée à un terminal), moins les sauts de ligne de fin.Le problème est que vous supprimez les sauts de ligne lorsque vous imprimez la valeur. Dans un script shell,
$LS
ne signifie pas «la valeur de la variableLS
», cela signifie «prendre la valeur deLS
, la diviser en mots selonIFS
et interpréter chaque mot comme un modèle global». Pour obtenir la valeur deLS
, vous devez écrire"$LS"
, ou plus généralement mettre$LS
entre guillemets doubles.echo "$LS"
imprime la valeur deLS
, sauf dans certains shells qui interprètent les caractères antislash, et à l'exception de quelques valeurs commençant par-
.printf "$LS"
imprime la valeurLS
tant qu'il ne contient pas de caractère de pourcentage ou de barre oblique inverse (et avec la plupart des implémentations) ne commence pas par-
.Pour imprimer la valeur de
LS
exactement, utilisezprintf %s "$LS"
. Si vous voulez une nouvelle ligne à la fin, utilisezprintf '%s\n' "$LS"
.Notez que ce
$(ls)
n'est pas, en général, la liste des fichiers dans le répertoire courant. Cela ne fonctionne que lorsque vous avez des noms de fichiers suffisamment apprivoisés. Pour obtenir la liste des noms de fichiers (sauf les fichiers de points), vous devez utiliser un caractère générique:*
. Le résultat est une liste de chaînes, pas une chaîne, vous ne pouvez donc pas l'affecter à une variable de chaîne; vous pouvez utiliser une variable de tableaufiles=(*)
dans des shells qui les prennent en charge (ksh93, bash, zsh).Pour plus d'informations, voir Pourquoi mon script shell s'étouffe-t-il avec les espaces ou d'autres caractères spéciaux?
la source
Ce qui précède
est la seule solution correcte.
Permettez-moi de démontrer que les autres solutions proposées, à la fois avec
echo
etprintf
, ne fonctionnent tout simplement pas correctement:(On peut également tester avec
V=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"
et variations.)Alors que
\n
les noms de fichiers peuvent ne pas être aussi courants, stockez-lesgit diff
dans une variable et vos chances de rencontrer littéralement\n
augmentent considérablement.la source
ksh
etzsh
également soutenirprint -r -- "$LS"
et azsh
égalementecho -E - $LS
.csh
aecho $LS:q
cependant que cela ne produit pas le caractère de nouvelle ligne si $ LS est vide, et obtenir une valeur multiligne dans $ LS en premier lieu est assez délicat dans csh.