Jak odczytać plik do zmiennej w powłoce?
Chcę odczytać plik i zapisać go w zmiennej, ale muszę zachować zmienną, a nie tylko wydrukować plik. Jak mogę to zrobić? Napisałem ten skrypt, ale nie jest to do końca to, czego potrzebowałem:
#!/bin/sh
while read LINE
do
echo $LINE
done <$1
echo 11111-----------
echo $LINE
W moim skrypcie mogę podać nazwę pliku jako parametr, więc jeśli plik zawiera np. "aaaa", to wypisuje to:
aaaa
11111-----
Ale to po prostu wypisuje plik na ekranie i chcę go zapisać do zmiennej! Czy jest na to łatwy sposób?
5 answers
W przekrojowym, NAJNIŻSZYM-wspólnym-mianowniku sh
używasz:
#!/bin/sh
value=`cat config.txt`
echo "$value"
W bash
lub zsh
, aby wczytać cały plik do zmiennej bez wywoływania cat
:
#!/bin/bash
value=$(<config.txt)
echo "$value"
Wywołanie cat
w bash
lub zsh
do slurp pliku byłoby uważane za bezużyteczne użycie Cat .
Zauważ, że nie jest konieczne cytowanie podstawienia polecenia, aby zachować nowe linie.
Zobacz: Bash Hacker ' s Wiki-Command substitution-Specialities .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-15 19:19:55
Jeśli chcesz wczytać cały plik do zmiennej:
#!/bin/bash
value=`cat sources.xml`
echo $value
Jeśli chcesz przeczytać wiersz po wierszu:
while read line; do
echo $line
done < file.txt
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-15 07:34:19
Dwie ważne pułapki
Które zostały dotychczas zignorowane przez inne odpowiedzi:
- końcowe usuwanie nowej linii z rozszerzenia poleceń
- usuwanie znaków NUL
Końcowe usuwanie nowej linii z rozszerzenia poleceń
To jest problem dla:
value="$(cat config.txt)"
Rozwiązania typu, ale nie dla rozwiązań opartych na read
.
Rozszerzenie polecenia usuwa końcowe newlines:
S="$(printf "a\n")"
printf "$S" | od -tx1
Wyjścia:
0000000 61
0000001
To łamie naiwną metodę odczytu z plików:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Obejście POSIX: dodanie dodatkowego znaku do rozszerzenia polecenia i usunięcie go później:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Wyjścia:
0000000 61 0a 0a
0000003
Prawie obejście POSIX: kodowanie ASCII. Patrz poniżej.
Usuwanie znaków NUL
Nie ma rozsądnego sposobu przechowywania znaków NUL w zmiennych .
[[16]}wpływa to zarówno na ekspansję, jak iread
rozwiązania, a ja nie znam żadnego dobrego obejścia tego problemu.
Przykład:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Wyjścia:
0000000 61 00 62
0000003
0000000 61 62
0000002
Ha, nasz NUL zniknął!
Obejścia:
Kodowanie ASCII. Patrz poniżej.
-
Użyj rozszerzenia bash
$""
literały:S=$"a\0b" printf "$S" | od -tx1
Działa tylko dla literałów, więc nie jest przydatny do czytania z plików.
Obejście pułapek
Przechowuj zakodowaną wersję uuencode base64 plik w zmiennej i dekodować przed każdym użyciem:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
Wyjście:
0000000 61 00 0a
0000003
Uuencode i udecode są POSIX 7 , ale domyślnie nie w Ubuntu 12.04 (pakietsharutils
)... Nie widzę alternatywy POSIX 7 dla rozszerzenia podstawienia procesu bash <()
z wyjątkiem zapisu do innego pliku...
Oczywiście jest to powolne i niewygodne, więc myślę, że prawdziwa odpowiedź brzmi: nie używaj Bash, jeśli plik wejściowy może zawierać znaki NUL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:37
Jak zauważa Ciro Santilli użycie podstawień poleceń spowoduje opuszczenie końcowych linii nowych. Ich obejście dodawanie końcowych znaków jest świetne, ale po dłuższym czasie użytkowania zdecydowałem, że potrzebuję rozwiązania, które w ogóle nie używa zastępowania poleceń.
Moje podejście {[7] } teraz używa read
wraz z printf
wbudowane -v
znacznik w celu wczytania zawartości stdin bezpośrednio do zmiennej.
# 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"
}
Obsługuje wejścia z lub bez końca newlines.
Przykładowe użycie:
$ read_input file_contents < /tmp/file
# $file_contents now contains the contents of /tmp/file
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-26 00:36:08
To działa na mnie:
v=$(cat <file_path>)
echo $v
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-30 22:46:54