Θέλω να διαβάσω ένα αρχείο και να το αποθηκεύσω σε μεταβλητή, αλλά πρέπει να κρατήσω τη μεταβλητή και όχι απλώς να εκτυπώσω το αρχείο. Πώς μπορώ να το κάνω αυτό; Έχω γράψει αυτό το σενάριο, αλλά δεν είναι ακριβώς αυτό που χρειαζόμουν:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
Στο σενάριό μου, μπορώ να δώσω το όνομα του αρχείου ως παράμετρο, έτσι, αν το αρχείο περιέχει "aaaa", για παράδειγμα, θα εκτυπώσει αυτό:
aaaa
11111-----
Αλλά αυτό απλώς εκτυπώνει το αρχείο στην οθόνη, ενώ εγώ θέλω να το αποθηκεύσω σε μια μεταβλητή! Υπάρχει κάποιος εύκολος τρόπος για να γίνει αυτό;
Σε cross-platform, ο χαμηλότερος κοινός παρονομαστής sh
που χρησιμοποιείτε:
#!/bin/sh
value=`cat config.txt`
echo "$value"
Σε bash
ή zsh
, για να διαβάσετε ένα ολόκληρο αρχείο σε μια μεταβλητή χωρίς να καλέσετε το cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
Η κλήση του cat
σε bash
ή zsh
για να ρουφήξετε ένα αρχείο θα θεωρούνταν Useless Use of Cat.
Σημειώστε ότι δεν είναι απαραίτητο να παραθέσετε σε εισαγωγικά την αντικατάσταση της εντολής για να διατηρήσετε τις νέες γραμμές.
Βλ: Bash Hacker's Wiki - Υποκατάσταση εντολών - Ειδικότητες.
Δύο σημαντικές παγίδες
οι οποίες αγνοήθηκαν από άλλες απαντήσεις μέχρι τώρα:
Αφαίρεση νέας γραμμής από την επέκταση εντολών
Αυτό είναι ένα πρόβλημα για το:
value="$(cat config.txt)"
αλλά όχι για τις λύσεις που βασίζονται στην "ανάγνωση".
Η επέκταση εντολών αφαιρεί τις τελικές νέες γραμμές:
S="$(printf "a\n")"
printf "$S" | od -tx1
Έξοδοι:
0000000 61
0000001
Αυτό σπάει την αφελή μέθοδο ανάγνωσης από αρχεία:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Λύση POSIX: προσθέστε ένα επιπλέον char στην επέκταση της εντολής και αφαιρέστε το αργότερα:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Έξοδοι:
0000000 61 0a 0a
0000003
Σχεδόν λύση POSIX: ASCII. Βλέπε παρακάτω.
Αφαίρεση του χαρακτήρα NUL
Δεν υπάρχει λογικός τρόπος Bash για την αποθήκευση χαρακτήρων NUL σε μεταβλητές.
Αυτό επηρεάζει τόσο την επέκταση όσο και τις λύσεις read
, και δεν γνωρίζω κάποια καλή λύση γι' αυτό.
Παράδειγμα:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Έξοδοι:
0000000 61 00 62
0000003
0000000 61 62
0000002
Χα, το NUL μας έφυγε!
Λύσεις:
ASCII. Βλέπε παρακάτω.
Χρησιμοποιήστε την επέκταση bash $""
κυριολεκτικά:
S=$"a\0b",
printf "$S" | od -tx1
Λειτουργεί μόνο για λογοτεχνικά, οπότε δεν είναι χρήσιμη για ανάγνωση από αρχεία.
Περιστροφή για τις παγίδες
Αποθηκεύστε μια κωδικοποιημένη με uuencode base64 έκδοση του αρχείου στη μεταβλητή και αποκωδικοποιήστε την πριν από κάθε χρήση:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
Έξοδος:
0000000 61 00 0a
0000003
Τα uuencode και udecode είναι POSIX 7 αλλά όχι στο Ubuntu 12.04 από προεπιλογή (πακέτο sharutils
)... Δεν βλέπω εναλλακτική λύση POSIX 7 για την επέκταση αντικατάστασης της διαδικασίας bash <()
εκτός από την εγγραφή σε άλλο αρχείο...
Φυσικά, αυτό είναι αργό και άβολο, οπότε υποθέτω ότι η πραγματική απάντηση είναι: μην χρησιμοποιείτε το Bash αν το αρχείο εισόδου μπορεί να περιέχει χαρακτήρες NUL.