Comment lire un fichier dans une variable du shell?

je veux lire un fichier et l'enregistrer dans une variable, mais j'ai besoin de garder la variable et pas seulement imprimer le fichier. Comment puis-je faire cela? 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 <  
echo 11111-----------  
echo $LINE  

Dans mon script, je peux donner le nom de fichier comme paramètre, donc, si le fichier contient "aaaa", par exemple, imprimer ceci:

aaaa
11111-----

Mais cela imprime le fichier sur l'écran, et je veux l'enregistrer dans un variable! Est-il un moyen facile de faire cela?

334
demandé sur Martin Tournoij 2011-09-15 11:29:16

5 réponses

dans cross-platform, le plus bas-commun-dénominateur sh vous utilisez:

#!/bin/sh
value=`cat config.txt`
echo "$value"

Dans bash ou zsh , à lire tout un fichier dans une variable, sans invoquer cat :

#!/bin/bash
value=$(<config.txt)
echo "$value"

invoquer cat dans bash ou zsh pour escamoter un fichier serait considéré comme une utilisation inutile de Cat .

Notez qu'il n'est pas nécessaire de citer la commande substitution pour préserver newlines.

Voir: Bash Hacker Wiki - la substitution de Commande - Spécialités .

744
répondu Alan Gutierrez 2017-02-15 19:19:55

si vous voulez lire l'ensemble du fichier dans une variable:

#!/bin/bash
value=`cat sources.xml`
echo $value

Si vous voulez le lire ligne par ligne:

while read line; do    
    echo $line    
done < file.txt
69
répondu brain 2011-09-15 07:34:19

deux pièges importants

qui ont été ignorés par d'autres réponses jusqu'à présent:

  1. retrait de newline de L'extension de commande
  2. NOL character removal

newline à L'arrière suppression de l'expansion du commandement

C'est un problème pour l':

value="$(cat config.txt)"

tapez les solutions, mais pas pour les solutions read .

l'extension de la commande supprime les lignes de nouvelle traînantes:

S="$(printf "a\n")"
printf "$S" | od -tx1

sorties:

0000000 61
0000001

cela brise la méthode naïve de lecture des fichiers:

FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"

solution POSIX: ajouter un char supplémentaire à l'extension de la commande et le supprimer plus tard:

S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1

sorties:

0000000 61 0a 0a
0000003

presque POSIX solution de contournement: code ASCII. Voir ci-dessous.

suppression du caractère NUL

il n'y a pas de façon sensée de stocker des caractères NUL dans les variables .

cela affecte à la fois l'expansion et les solutions read , et je ne connais pas de bonne solution.

exemple:

printf "a"151960920"b" | od -tx1
S="$(printf "a"151960920"b")"
printf "$S" | od -tx1

sorties:

0000000 61 00 62
0000003

0000000 61 62
0000002

Ha, notre numéro est parti!

Solutions de contournement:

  • ASCII encode. Voir ci-dessous.

  • utiliser bash extension $"" littéraux:

    S=$"a"151980920"b"
    printf "$S" | od -tx1
    

    ne fonctionne que pour la littérature, donc pas utile pour la lecture à partir de fichiers.

contourner les pièges

stocker une version codée uuencode base64 du fichier dans la variable, et décoder avant chaque usage:

FILE="$(mktemp)"
printf "a"151990920"\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"

sortie:

0000000 61 00 0a
0000003

uuencode et udecode sont POSIX 7 mais pas dans Ubuntu 12.04 par défaut (paquet sharutils )... Je ne vois pas D'alternative POSIX 7 pour l'extension de substitution de bash <() , sauf pour écrire dans un autre fichier...

bien sûr, c'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.

58

Comme Ciro Santilli notes utilisation de la commande de substitution ne baisse de fuite des retours à la ligne. Leur façon de contourner l'ajout de caractères de fuite 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'utilise pas du tout la substitution de commandes.

Mon approche utilise maintenant read avec la printf builtin -v drapeau dans le but de lire le contenu de stdin directement dans une variable.

# Reads stdin into a variable, accounting for trailing newlines. Avoids needing a subshell or
# command substitution.
read_input() {
  # Use unusual variable names to avoid colliding with a variable name
  # the user might pass in (notably "contents")
  : "${1:?Must provide a variable to read into}"
  if [[ "" == '_line' || "" == '_contents' ]]; then
    echo "Cannot store contents to , use a different name." >&2
    return 1
  fi

  local _line _contents
   while read -r _line; do
     _contents="${_contents}${_line}"$'\n'
   done
   _contents="${_contents}${_line}" # capture any content after the last newline
   printf -v "" '%s' "$_contents"
}

ce système prend en charge les entrées avec ou sans lignes de fuite.

exemple d'usage:

$ read_input file_contents < /tmp/file
# $file_contents now contains the contents of /tmp/file
1
répondu dimo414 2018-04-26 00:36:08

ça marche pour moi: v=$(cat <file_path>) echo $v

0
répondu angelo.mastro 2018-08-30 22:46:54