Chcem načítať súbor a uložiť ho do premennej, ale potrebujem zachovať premennú a nie len vypísať súbor. Ako to môžem urobiť? Napísal som tento skript, ale nie je to celkom to, čo som potreboval:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
V mojom skripte môžem ako parameter zadať názov súboru, takže ak súbor obsahuje napríklad "aaaa", vypíše to toto:
aaaa
11111-----
Ale to len vypíše súbor na obrazovku a ja ho chcem uložiť do premennej! Existuje nejaký jednoduchý spôsob, ako to urobiť?
V multiplatformovom systéme používate najmenší spoločný menovateľ sh
:
#!/bin/sh
value=`cat config.txt`
echo "$value"
V bash
alebo zsh
na načítanie celého súboru do premennej bez vyvolania cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
Vyvolanie cat
v bash
alebo zsh
na prehltnutie súboru by sa považovalo za Useless Use of Cat.
Všimnite si, že na zachovanie nových riadkov nie je potrebné substitúciu príkazu uvádzať v úvodzovkách.
Pozri: Bash Hacker's Wiki - Command substitution - Specialities.
Dve dôležité nástrahy
ktoré ostatné odpovede doteraz ignorovali:
Odstránenie koncového nového riadku z expanzie príkazu
Toto je problém pre:
value="$(cat config.txt)"
ale nie pre riešenia založené na čítaní
.
Rozšírenie príkazu odstraňuje koncové nové riadky:
S="$(printf "a\n")"
printf "$S" | od -tx1
Výstupy:
0000000 61
0000001
Tým sa poruší naivná metóda čítania zo súborov:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Riešenie POSIX: Pridajte ďalší znak k rozšíreniu príkazu a odstráňte ho neskôr:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Výstupy:
0000000 61 0a 0a
0000003
Takmer POSIXové riešenie: ASCII kódovanie. Pozri nižšie.
Odstránenie znaku NUL
Neexistuje žiadny rozumný spôsob, ako ukladať znaky NUL v premenných.
Toto sa týka riešení expanzie aj čítania
a nepoznám žiadne dobré riešenie.
Príklad:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Výstupy:
0000000 61 00 62
0000003
0000000 61 62
0000002
Ha, náš NUL je preč!
Obchádzanie problémov:
ASCII kódovanie. Pozri nižšie.
použite rozšírenie bash $""
literály:
S=$"a\0b"
printf "$S" | od -tx1
Funguje len pre literály, takže nie je užitočné pre čítanie zo súborov.
Obídenie nástrah
Ukladajte do premennej verziu súboru v kódovaní base64 uuencode a pred každým použitím ju dekódujte:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
Výstup:
0000000 61 00 0a
0000003
uuencode a udecode sú POSIX 7, ale v Ubuntu 12.04 štandardne nie sú (balík sharutils
)... Nevidím žiadnu alternatívu POSIX 7 pre rozšírenie bash procesu <()
substitúcie okrem zápisu do iného súboru...
Samozrejme, je to pomalé a nepohodlné, takže hádam skutočná odpoveď znie: nepoužívajte Bash, ak vstupný súbor môže obsahovať znaky NUL.