J'ai un fichier texte test.txt avec le contenu suivant:
text1
text2
Et je veux assigner le contenu du fichier à une variable UNIX, mais quand je fais ceci:
testvar=$(cat test.txt)
echo $testvar
le résultat est:
text1 text2
au lieu de
text1
text2
Quelqu'un peut-il me proposer une solution pour cela?
L'affectation ne supprime pas les caractères de nouvelle ligne not, il s'agit en réalité de la echo
. Vous devez simplement mettre des guillemets autour de la chaîne pour conserver ces nouvelles lignes:
echo "$testvar"
Cela donnera le résultat que vous voulez. Voir la transcription suivante pour une démo:
pax> cat num1.txt ; x=$(cat num1.txt)
line 1
line 2
pax> echo $x ; echo '===' ; echo "$x"
line 1 line 2
===
line 1
line 2
La raison pour laquelle les nouvelles lignes sont remplacées par des espaces n'est pas entièrement à voir avec la commande echo
, mais plutôt une combinaison de choses.
Lorsqu'une ligne de commande est donnée, bash
la divise en mots conformément à la documentation de la variable IFS
:
IFS: Séparateur de champ interne utilisé pour le fractionnement de Word après le développement ... la valeur par défaut est
<space><tab><newline>
.
Cela spécifie que, par défaut, n'importe lequel de ces trois caractères peut être utilisé pour fractionner votre commande en mots individuels. Après cela, les séparateurs de mots ont disparu, il ne vous reste plus qu'une liste de mots.
Combinez cela avec la documentation echo
(une commande interne bash
) et vous verrez pourquoi les espaces sont affichés:
echo [-neE] [arg ...]: Affiche les arguments, séparés par des espaces, suivis d'une nouvelle ligne.
Lorsque vous utilisez echo "$x"
, la variable x
entière est forcée à être un single Word conformément à bash
. Par conséquent, il n'est pas divisé. Vous pouvez voir cela avec:
pax> function count {
...> echo $#
...> }
pax> count 1 2 3
3
pax> count a b c d
4
pax> count $x
4
pax> count "$x"
1
Ici, la fonction count
affiche simplement le nombre d'arguments donnés. Les variantes 1 2 3
et a b c d
le montrent en action.
Ensuite, nous l’essayons avec les deux variations de la variable x
. Le guillemet sans indique qu'il y a quatre mots, "test"
, "1"
, "test"
et "2"
. L'ajout des guillemets rend un un seul mot "test 1\ntest 2"
.
Cela est dû à IFS (séparateur de champs internes) variable qui contient une nouvelle ligne.
$ cat xx1
1
2
$ A=`cat xx1`
$ echo $A
1 2
$ echo "|$IFS|"
|
|
Une solution de contournement consiste à réinitialiser IFS pour ne pas contenir la nouvelle ligne, temporairement:
$ IFSBAK=$IFS
$ IFS=" "
$ A=`cat xx1` # Can use $() as well
$ echo $A
1
2
$ IFS=$IFSBAK
Pour inverser ce changement horrible pour IFS:
IFS=$IFSBAK
Bash -ge 4 a le mapfile intégré pour lire les lignes de l’entrée standard dans une variable tableau.
help mapfile
mapfile < file.txt lines
printf "%s" "${lines[@]}"
mapfile -t < file.txt lines # strip trailing newlines
printf "%s\n" "${lines[@]}"
Voir également:
http://bash-hackers.org/wiki/doku.php/commands/builtin/mapfile
Votre variable est définie correctement par testvar=$(cat test.txt)
. Pour afficher cette variable composée de nouveaux caractères de ligne, ajoutez simplement des guillemets, par exemple.
echo "$testvar"
Voici l'exemple complet:
$ printf "test1\ntest2" > test.txt
$ testvar=$(<test.txt)
$ grep testvar <(set)
testvar=$'test1\ntest2'
$ echo "$testvar"
text1
text2
$ printf "%b" "$testvar"
text1
text2
Juste si quelqu'un est intéressé par une autre option:
content=( $(cat test.txt) )
a=0
while [ $a -le ${#content[@]} ]
do
echo ${content[$a]}
a=$[a+1]
done
L'utilitaire envdir
fournit un moyen simple de procéder. envdir
utilise des fichiers pour représenter les variables d'environnement, les noms de fichier étant mappés sur les noms env var et le contenu du fichier sur les valeurs env var Si le contenu du fichier contient des retours à la ligne, env var.