Je veux lire un fichier et le sauvegarder dans une variable, mais je dois conserver la variable et ne pas simplement 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 <$1
echo 11111-----------
echo $LINE
Dans mon script, je peux donner le nom du fichier en tant que paramètre. Ainsi, si le fichier contient "aaaa", par exemple, il affichera ceci:
aaaa
11111-----
Mais cela ne fait qu'imprimer le fichier à l'écran et je souhaite le sauvegarder dans une variable! Y a-t-il un moyen simple de le faire?
Dans la multiplate-forme, le plus petit commun dénominateur sh
, vous utilisez:
#!/bin/sh
value=`cat config.txt`
echo "$value"
Dans bash
ou zsh
, pour lire un fichier entier dans une variable sans appeler cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
Invoquer cat
dans bash
ou zsh
à Slurp un fichier serait considéré comme un Utilisation inutile de Cat .
Notez qu'il n'est pas nécessaire de citer la substitution de commande pour conserver les nouvelles lignes.
Voir: Wiki de Bash Hacker - Substitution de commande - Spécialités .
Si vous voulez lire le fichier entier 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
Deux pièges importants
qui ont été ignorés par d'autres réponses jusqu'à présent:
Fin de suppression de nouvelle ligne du développement de la commande
C'est un problème pour le:
value="$(cat config.txt)"
type solutions, mais pas pour les solutions à base read
.
L'extension de commande supprime les retours à la ligne:
S="$(printf "a\n")"
printf "$S" | od -tx1
Les sorties:
0000000 61
0000001
Cela rompt la méthode naïve de lecture de fichiers:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Solution palliative POSIX: ajoutez un caractère supplémentaire au développement de la commande et supprimez-le ultérieurement:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Les sorties:
0000000 61 0a 0a
0000003
Solution de contournement presque POSIX: ASCII encoder. Voir ci-dessous.
Suppression de caractères NUL
Il n'y a pas de moyen sûr Bash de stocker les caractères NUL dans les variables .
Cela affecte à la fois les solutions d’extension et read
, et je ne connais aucune solution de contournement satisfaisante.
Exemple:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Les sorties:
0000000 61 00 62
0000003
0000000 61 62
0000002
Ha, notre NUL est parti!
Solutions de contournement:
ASCII encoder. Voir ci-dessous.
utilisez les littéraux de bash extension $""
:
S=$"a\0b"
printf "$S" | od -tx1
Ne fonctionne que pour les littéraux, donc pas utile pour lire des fichiers.
Solution de contournement pour les pièges
Stockez une version encodée en base64 du fichier dans la variable et décodez-la avant chaque utilisation:
FILE="$(mktemp)"
printf "a\0\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 <()
du processus bash, sauf l'écriture dans un autre fichier ...
Bien sûr, c'est lent et peu pratique, alors je suppose que la vraie réponse est: n'utilisez pas Bash si le fichier d'entrée peut contenir des caractères NUL.
cela fonctionne pour moi:
v=$(cat <file_path>)
echo $v
Comme Ciro Santilli note , l’utilisation de substitutions de commandes supprimera les retours à la ligne. Leur solution de contournement en ajoutant des caractères de fin est géniale, mais après l'avoir utilisée pendant un certain temps, j'ai décidé que j'avais besoin d'une solution qui n'utilisait pas du tout le remplacement de commande.
Mon approche utilise maintenant read
avec l'indicateur printf
builtin's -v
afin 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 [[ "$1" == '_line' || "$1" == '_contents' ]]; then
echo "Cannot store contents to $1, 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 "$1" '%s' "$_contents"
}
Ceci prend en charge les entrées avec ou sans nouvelles lignes.
Exemple d'utilisation:
$ read_input file_contents < /tmp/file
# $file_contents now contains the contents of /tmp/file