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?

 334
Author: Martin Tournoij, 2011-09-15

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 .

 744
Author: Alan Gutierrez,
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
 69
Author: brain,
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:

  1. końcowe usuwanie nowej linii z rozszerzenia poleceń
  2. 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 i read 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.

 58
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
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
 1
Author: dimo414,
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

 0
Author: angelo.mastro,
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