Je veux lire un fichier et l'enregistrer dans une variable, mais je dois conserver la variable et pas seulement imprimer le fichier. Comment puis-je faire ceci? J'ai écrit ce script mais ce n'est pas tout à fait ce dont j'avais besoin:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
Dans mon script, je peux donner le nom du fichier comme paramètre, donc, si le fichier contient "aaaa", par exemple, il afficherait ceci:
aaaa
11111-----
Mais cela imprime simplement le fichier à l'écran et je veux l'enregistrer dans une variable! Y a-t-il un moyen facile de faire ceci?
cat
ou$(<someFile)
se traduira par une sortie incomplète ( la taille est inférieure à celle du fichier réel).Réponses:
Dans le plus petit dénominateur commun multiplateforme que
sh
vous utilisez:Dans
bash
ouzsh
, pour lire un fichier entier dans une variable sans invoquercat
:L' appel
cat
dansbash
ouzsh
à slurp un fichier serait considéré comme un Useless utilisation de Cat .Notez qu'il n'est pas nécessaire de citer la substitution de commande pour conserver les retours à la ligne.
Voir: Wiki de Bash Hacker - Substitution de commandes - Spécialités .
la source
value="`cat config.txt`"
etvalue="$(<config.txt)"
plus sûr dans le cas où config.txt contient des espaces?cat
comme ci-dessus n'est pas toujours considérée comme une utilisation inutile decat
. Par exemple,< invalid-file 2>/dev/null
entraînera un message d'erreur qui ne peut pas être acheminé vers/dev/null
, alorscat invalid-file 2>/dev/null
qu'il est correctement acheminé vers/dev/null
.value=$(<config.txt)
c'est bien, maisvalue = $(<config.txt)
c'est mauvais. Attention à ces espaces.Si vous souhaitez lire l'intégralité du fichier dans une variable:
Si vous souhaitez le lire ligne par ligne:
la source
echo "$value"
. Sinon, le shell effectuera la tokenisation des espaces et l'expansion des caractères génériques sur la valeur.read -r
au lieu de justeread
- toujours, sauf si vous avez spécifiquement besoin du comportement hérité étrange auquel vous faites allusion.Deux écueils importants
qui ont été ignorées par d'autres réponses jusqu'à présent:
Suppression de la nouvelle ligne de fin de l'extension de commande
C'est un problème pour:
solutions de type, mais pas pour les
read
solutions basées.L'expansion de la commande supprime les nouvelles lignes de fin:
Les sorties:
Cela rompt la méthode naïve de lecture à partir de fichiers:
Solution de contournement POSIX: ajoutez un caractère supplémentaire à l'extension de commande et supprimez-le ultérieurement:
Les sorties:
Solution de contournement presque POSIX: encodage ASCII. Voir ci-dessous.
Suppression de caractère NUL
Il n'y a aucun moyen sain et simple de stocker des caractères NUL dans des variables .
Cela affecte à la fois l'expansion et les
read
solutions, et je ne connais pas de bonne solution de contournement.Exemple:
Les sorties:
Ha, notre NUL est parti!
Solutions de contournement:
Encodage ASCII. Voir ci-dessous.
utilisez les
$""
littéraux d' extension bash :Fonctionne uniquement pour les littéraux, donc pas utile pour lire à partir de fichiers.
Solution aux écueils
Stockez une version encodée en uuencode base64 du fichier dans la variable et décodez avant chaque utilisation:
Production:
uuencode et udecode sont POSIX 7 mais pas dans Ubuntu 12.04 par défaut (
sharutils
package) ... Je ne vois pas d'alternative POSIX 7 pour l'<()
extension de substitution de processus bash sauf pour écrire dans un autre fichier ...Bien sûr, cela est lent et peu pratique, donc je suppose que la vraie réponse est: n'utilisez pas Bash si le fichier d'entrée peut contenir des caractères NUL.
la source
S="$(printf "\\\'\"")"; echo $S
. Sortie:\'"
. Donc ça marche =)$()
expansion, mon exemple montre que l'$()
expansion fonctionne avec\'"
.cela fonctionne pour moi:
v=$(cat <file_path>) echo $v
la source
Comme le note Ciro Santilli, l' utilisation de substitutions de commandes supprimera les nouvelles lignes de fin. Leur solution de contournement ajoutant des caractères de fin est excellente, mais après l'avoir utilisé pendant un certain temps, j'ai décidé que j'avais besoin d'une solution qui n'utilisait pas du tout la substitution de commandes.
Mon approche utilise maintenant
read
avec le drapeauprintf
intégré afin de lire le contenu de stdin directement dans une variable.-v
Cela prend en charge les entrées avec ou sans retour à la ligne.
Exemple d'utilisation:
la source
_contents="${_contents}${_line}\n "
pour préserver les nouvelles lignes?$'\n'
? C'est nécessaire, sinon vous ajoutez du littéral\
et desn
caractères. Votre bloc de code a également un espace supplémentaire à la fin, vous ne savez pas si c'est intentionnel, mais il indenterait chaque ligne suivante avec un espace supplémentaire.Vous pouvez accéder à 1 ligne à la fois par boucle
Copiez tout le contenu dans File (disons line.sh); Exécuter
la source
for
boucle ne boucle pas sur les lignes, elle boucle sur les mots. Dans le cas de/etc/passwd
, il arrive que chaque ligne ne contienne qu'un seul mot. Cependant, d'autres fichiers peuvent contenir plusieurs mots par ligne.