Czy mogę sprawić, by „cut” zmienił plik na miejscu?


Odpowiedzi:


14

Nie możesz Użyj ed lub GNU sed lub perl albo zrób to, co robią za kulisami, czyli utworzenie nowego pliku dla zawartości.

ed, przenośny:

ed foo <<EOF
1,$s/^\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/
w
q
EOF

GNU ANTYLOPA sed :

sed -i -e 's/^\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/' foo

Perl:

perl -i -l -F, -pae 'print @F[1,3]' foo

cut, tworzenie nowego pliku (zalecane, ponieważ jeśli twój skrypt zostanie przerwany, możesz go ponownie uruchomić):

cut -d , -f 1,3 <foo >foo.new &&
mv -f foo.new foo

cut, zastępując plik na miejscu (zachowuje własność i uprawnienia foo, ale potrzebuje ochrony przed przerwami):

cp -f foo foo.old &&
cut -d , -f 1,3 <foo.old >foo &&
rm foo.old

Polecam użycie jednej z cutmetod opartych na bazie . W ten sposób nie polegasz na żadnym niestandardowym narzędziu, możesz użyć najlepszego narzędzia do pracy i kontrolować zachowanie podczas przerwania.


Lepsza niż .oldmetoda wprowadzania zmian w miejscu,echo "$(cut -d , -f 1,3 <foo)" > foo
GypsyCosmonaut

1
@GypsyCosmonaut Nie, to nie jest „lepsze”. To jest bardziej delikatne. Jego jedyną zaletą jest to, że jest krótszy do pisania. Głównym problemem związanym z tą metodą jest to, że jeśli wystąpi błąd podczas przetwarzania pliku wejściowego lub zapisu wyniku, dane zostaną utracone. Nie działa również z danymi binarnymi: dane wyjściowe zostaną obcięte przy pierwszym bajcie zerowym. Nawet w przypadku plików tekstowych usuwa puste linie z końca pliku. W przypadku dużych plików może się nie powieść, ponieważ dane muszą być przechowywane jako ciąg w pamięci powłoki (i pamiętaj, że jeśli tak się stanie, dane zostaną utracone).
Gilles „SO- przestań być zły”

oO Dzięki, nie wiedziałem, że mogą być problemy z zerowym bajtem
GypsyCosmonaut

Myślę, że jest to prostsze:cut -d , -f 1,3 foo > foo.new rm foo mv foo.new foo
LoMaPh

@ LoMaPh Rzeczywiście, nie wiem, dlaczego zmieniłem nazwę starego pliku: nie ma on żadnych zalet w stosunku do zmiany nazwy nowego pliku. Jest to również prostsze, ponieważ nie potrzebujesz kroku rm foo. I nie powinieneś dzwonić rm foo, ponieważ mv foo.new foojest atomowy: usuwa starą wersję i jednocześnie umieszcza nową.
Gilles „SO- przestań być zły”

23

Moreutils pakiet z Ubuntu (a także debian ) posiada program o nazwie sponge, która sort-of rozwiązuje również problem.

Z gąbki męskiej:

sponge odczytuje standardowe wejście i zapisuje je w określonym pliku. W przeciwieństwie do przekierowania powłoki, gąbka wchłania wszystkie dane wejściowe przed otwarciem pliku wyjściowego. Umożliwia to zwężenie potoków, które odczytują i zapisują do tego samego pliku.

Co pozwoli ci zrobić coś takiego:

cut -d <delim> -f <fields> somefile | sponge somefile

9

Nie sądzę, że jest to możliwe przy użyciu cutsamego. Nie mogłem tego znaleźć na stronie o człowieku lub stronie informacyjnej. Możesz zrobić coś takiego jak

mytemp=$(mktemp) && cut -d" " -f1 file > $mytemp && mv $mytemp file

mktemptworzy względnie bezpieczny plik tymczasowy, do którego można potokować dane cutwyjściowe.


1

Wypróbuj vim-way:

$ ex -s +'%!cut -c 1-10' -cxa file.txt

Spowoduje to edycję pliku w miejscu (najpierw wykonaj kopię zapasową).

Alternatywnie można zastosować grep, sedlub gawk.



0

Cóż, ponieważ cutprodukuje mniej danych wyjściowych niż czyta, możesz:

cut -c1 < file 1<> file

Oznacza to, że stdin powinien być fileotwarty w trybie tylko do odczytu, a stdout fileotwarty w trybie odczytu + zapisu bez obcinania ( <>).

W ten sposób cutpo prostu nadpisze plik na siebie. Pozostawia jednak pozostałą część pliku niezmienioną. Na przykład, jeśli filezawiera:

foo
bar

Dane wyjściowe staną się:

f
b
bar

f\nb\nZastąpiły foo\n, ale barnadal istnieje. Po tym musisz przyciąć plikcut skończyć zakończeniu.

Za pomocą ksh93można to zrobić za pomocą <>;operatora, który działa podobnie, <>z tym wyjątkiem, że jeśli polecenie się powiedzie, ftruncate()wywoływany jest w deskryptorze pliku. Więc:

cut -c1 < file 1<>; file

W przypadku innych powłok należy wykonać ftruncate()inne czynności, takie jak:

{ cut -c1 < file; perl -e 'truncate STDOUT, tell STDOUT';} 1<> file

chociaż wywoływanie perltylko w tym celu jest nieco przesadne, szczególnie biorąc pod uwagę, że perlmożna z łatwością wykonać taką cutpracę, jak:

perl -pi -e '$_ = substr($_, 0, 1)' file

Uważaj, że przy wszystkich metodach, które wymagają faktycznego przepisywania w miejscu, jeśli operacja zostanie przerwana w połowie, skończysz na uszkodzonym pliku. Użycie tymczasowego drugiego pliku pozwala uniknąć tego problemu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.