Powłoka - zapisuje zmienną zawartość do pliku

98

Chciałbym skopiować zawartość zmiennej (nazywanej tutaj var) do pliku.

Nazwa pliku jest przechowywana w innej zmiennej destfile.

Mam z tym problem. Oto, czego próbowałem:

cp $var $destfile

Próbowałem też tego samego z poleceniem dd ... Oczywiście powłoka pomyślała, że $varodnosi się do katalogu, więc powiedziała mi, że nie można znaleźć katalogu.

Jak mam to obejść?

user1546083
źródło
2
Popraw swoje pytanie, publikując odpowiednio sformatowany kod, który pokazuje sposób wypełniania zmiennych oraz wszystkie istotne komunikaty o błędach dokładnie tak, jak się pojawiają.
Todd A. Jacobs
2
Co masz na myśli, mówiąc „kopiuj zawartość zmiennej” do katalogu? Czy $varokreśla nazwę pliku lub tekst, który powinien zostać zapisany w pliku? Jeśli określa tekst, to jaka jest nazwa pliku, do którego chcesz zapisać tę treść?
jahroy
Zmienna $ var zawiera tekst, który chcę skopiować, a plik, do którego powinien zostać zapisany, jest zdefiniowany przez użytkownika, stąd powód, dla którego używam zmiennej w pierwszej kolejności.
user1546083
1
Być może $destdirpowinno być nazwane, $destfileaby nie wprowadzało w błąd ... Nazwa $destdirsugeruje, że określa katalog, a nie plik. To sprawi, że całe twoje pytanie będzie jasne i łatwe do zrozumienia.
jahroy

Odpowiedzi:

150

Użyj echopolecenia:

var="text to append";
destdir=/some/directory/path/filename

if [ -f "$destdir" ]
then 
    echo "$var" > "$destdir"
fi

Do iftestów, które $destdirreprezentuje plik.

>Dołącza tekst po obcinanie pliku. Jeśli chcesz tylko dołączyć tekst $vardo istniejącej zawartości pliku, użyj >>zamiast tego:

echo "$var" >> "$destdir"

cpPolecenie służy do kopiowania plików (plików), a nie do pisania tekstu do pliku.

pb2q
źródło
4
Potrzebuje więcej cudzysłowów - w tej chwili wszelkie serie białych znaków w wartości zmiennej zostaną przekonwertowane na pojedynczą spację, wyrażenia glob zostaną rozszerzone itp.
Charles Duffy.
2
Jeszcze jedno - potrzebujesz spacji między cudzysłowem zamykającym a ]in "$destdir"].
Charles Duffy,
3
echododaje również końcowy znak nowej linii do zmiennej.
Ben Dilts,
6
To się nie powiedzie, jeśli tak $varjest -e text to append, i tak naprawdę nie pisze-e
Eric
1
Ponieważ echo $varpolega na rozszerzeniu zmiennej przez powłokę, nie działa to zbyt dobrze w przypadku takich rzeczy, jak białe znaki i znaki specjalne. Możesz użyć perl -e 'print($ENV{var})'zamiast tego, a wyświetli dokładnie wartość zmiennej.
Blake Mitchell
41

echoma problem, że jeśli varzawiera coś podobnego -e, zostanie zinterpretowane jako flaga. Inną opcją jest printf, ale printf "$var" > "$destdir"rozwinie wszelkie znaki ucieczki w zmiennej, więc jeśli zmienna zawiera ukośniki odwrotne, zawartość pliku nie będzie zgodna. Jednak, ponieważ printfodwrotne ukośniki są interpretowane tylko jako znaki specjalne w ciągu formatu, można użyć specyfikatora %sformatu do przechowywania dokładnej zawartości zmiennej w pliku docelowym:

printf "%s" "$var" > "$destdir"

Trebawa
źródło
1
printf jest również dobry, jeśli masz znaki nowej linii w zmiennej łańcuchowej, na przykład z potrójnego cudzysłowu lub heredoc. echo nie obsługuje dobrze nowych linii.
beeflobill
@beeflobill, czy możesz wyjaśnić, dlaczego „echo nie obsługuje dobrze nowych linii”. Jedyne, co widziałem, to to, że echo dodaje nową linię. Co robi echo "$var" > destfileźle.
SensorSmith
@SensorSmith W moich eksperymentach widzę, że kiedy łańcuch ma "\ n", to echo wypisze znak nowej linii. Ale jeśli łańcuch ma rzeczywisty znak nowej linii, to echo go nie wydrukuje. Nie wiem dlaczego.
beeflobill
1
Zasadniczo problem z przenośnością (i niezawodnością). unix.stackexchange.com/a/65819… lub dla zabójczych z nas: printfjest lepiej, idź dalej.
user3342816
30

Żadna z powyższych odpowiedzi nie działa, jeśli zmienna:

  • zaczynać z -e
  • zaczynać z -n
  • zaczynać z -E
  • zawiera a, \po którym następujen
  • nie powinien mieć dodawanego po nim dodatkowego znaku nowej linii

dlatego nie można na nich polegać w przypadku arbitralnej zawartości ciągów.

W bashu możesz użyć „ciągów tutaj” jako:

cat <<< "$var" > "$destdir"

Jak zauważono w komentarzu poniżej, odpowiedź @ Trebawa (sformułowana w tym samym pokoju co moja!) printfJest lepszym podejściem.

Eric
źródło
5
Z tego, co wiem, cat zawsze wstawia nową linię na końcu pliku, niezależnie od tego, czy na końcu zmiennej nie ma nowej linii (chociaż prawdopodobnie jest to dobra rzecz w większości przypadków). Odpowiedź za pomocą printf wydaje się uniknąć wstawienie nowej linii spływu.
Ash
@Ash kolejna zaleta printfna catto, że były to wbudowane powłoki, która zawsze będzie wykonać szybciej niż zewnętrznego binarny.
Géza Török
7

Jeśli dobrze cię zrozumiałem, chcesz skopiować $vardo pliku (jeśli jest to ciąg).

echo $var > $destdir
qwertz
źródło
Tak to się robi. Użycie tego cppolecenia spowoduje, że powłoka zinterpretuje pierwszy argument jako nazwę pliku lub katalogu.
jahroy
5
Jeśli nie ująłbyś go $varw cudzysłów, zawartość pliku nie jest w 100% równa zawartości zmiennej $ var w niektórych przypadkach. Na przykład, gdy "echo" vars zawiera klucze RSA, otrzymasz nieprawidłowy klucz w pliku.
srigi,
6
Zawodzi, jeśli $varzawiera spacje lub-e
Eric
1

Kiedy mówisz „kopiuj zawartość zmiennej”, czy ta zmienna zawiera nazwę pliku, czy też nazwę pliku?

Zakładam, że Twoje pytanie $varzawiera zawartość, którą chcesz skopiować do pliku:

$ echo "$var" > "$destdir"

Spowoduje to odzwierciedlenie wartości $ var w pliku o nazwie $ destdir. Zwróć uwagę na cytaty. Bardzo ważne jest, aby znak „$ zmienna” był ujęty w cudzysłów. Również dla „$ destdir”, jeśli w nazwie jest spacja. Aby dołączyć:

$ echo "$var" >> "$destdir"
David W.
źródło
3
Zawodzi, jeśli varzawiera-e
Eric
1
Przekazanie podwójnego łącznika jako pierwszego argumentu echo kończącego listę opcji, rozwiązuje w ten sposób problem poruszony przez @Eric:echo -- "$var" >> "$destfile"
Géza Török
1

Wszystkie powyższe działają, ale muszą również obejść problem (znaki specjalne i znaki specjalne), który nie musi występować w pierwszej kolejności: Znaki specjalne, gdy zmienna jest rozwijana przez powłokę. Po prostu tego nie rób (rozwijanie zmiennych) w pierwszej kolejności. Użyj zmiennej bezpośrednio, bez rozwijania.

Ponadto, jeśli zmienna zawiera sekret i chcesz skopiować ten sekret do pliku, możesz chcieć nie używać interpretacji w wierszu poleceń, ponieważ śledzenie / echo poleceń poleceń powłoki może ujawnić sekret. Oznacza to, że wszystkie odpowiedzi, które są używane $varw wierszu poleceń, mogą stwarzać potencjalne zagrożenie bezpieczeństwa, narażając zawartość zmiennej na śledzenie i rejestrowanie powłoki.

Użyj tego:

printenv var >file

Oznacza to, że w przypadku pytania PO:

printenv var >"$destfile"
Christian Hujer
źródło