Odczytywanie wierszy z pliku tekstowego i tworzenie pliku tekstowego dla każdej nazwy w każdym wierszu

21

Powiedzmy, że mam plik tekstowy taki jak:

john
george
james
stewert

z każdym imieniem w osobnym wierszu.

Chcę przeczytać wiersze tego pliku tekstowego i utworzyć plik tekstowy dla każdej nazwy, jak: john.txt, george.txtetc.

Jak mogę to zrobić w Bash?

levato
źródło
2
Potrzebujesz rozszerzenia? W systemie Linux nie ma powodu, aby pliki tekstowe miały rozszerzenie txt.
terdon

Odpowiedzi:

18

# 1 Korzystanie z Bash + touch:

while read line; do touch "$line.txt"; done <in
  • while read line; [...]; done <in: Działa, readdopóki readnie zwróci się samo 1, co dzieje się, gdy osiągnięty zostanie koniec pliku; dane wejściowe dla readodczytywane są z pliku o nazwie inw bieżącym katalogu roboczym zamiast z terminala z powodu <inprzekierowania;
  • touch "$line.txt": Działa touchna podstawie wartości rozszerzonej $line.txt, która jest zawartością, linepo której następuje .txt; touchutworzy plik, jeśli nie istnieje, i zaktualizuje jego czas dostępu, jeśli istnieje;

# 2 Używając xargs+ touch:

xargs -a in -I name touch name.txt
  • -a in: powoduje xargsodczyt danych wejściowych z pliku o nazwie inw bieżącym katalogu roboczym;
  • -I name: powoduje xargszastąpienie każdego wystąpienia namebieżącym wierszem wejściowym w następującym poleceniu;
  • touch name: Działa touchna zastąpionej wartości name; utworzy plik, jeśli nie istnieje, i zaktualizuje jego czas dostępu, jeśli istnieje;
% ls
in
% cat in
john
george
james
stewert
% while read line; do touch "$line.txt"; done <in
% ls
george.txt  in  james.txt  john.txt  stewert.txt
% rm *.txt
% xargs -a in -I name touch name.txt
% ls
george.txt  in  james.txt  john.txt  stewert.txt
kos
źródło
jak read linefaktycznie przeczyta wiersz? @kos
kashish
@kashish <inpo donemarki readw whilewarunku pętli przeczytać i przechowywać jedną linię ze inw lineprzy każdej iteracji; w ten sposób touch "$line.txt"wewnątrz pętli zostanie rozwinięty do linii odczytu .txtna końcu.
Kos
czy while read line; do touch "$line.txt"; done <insam sobie poradzi? Gdzie jest plik źródłowy?
kaszish
@kashish Oczywiście, są to metody alternatywne: masz na celu użycie jednego lub drugiego.
Kos
1
@kashish tak to readdziała. Zobaczyć help read.
terdon
18

W tym szczególnym przypadku, gdy masz tylko jedno słowo w wierszu, możesz także:

xargs touch < file

Pamiętaj, że to się zepsuje, jeśli twoje nazwy plików mogą zawierać spacje. W takich przypadkach użyj tego zamiast:

xargs -I {} touch {} < file

Dla zabawy, oto kilka innych podejść (oba mogą obsługiwać dowolne nazwy plików, w tym wiersze ze spacjami):

  • Perl

    perl -ne '`touch "$_"`' file
  • Awk

    awk '{printf "" > $0}' file 

Należy pamiętać, że w systemie Linux i podobnych systemach rozszerzenie jest opcjonalne dla większości plików. Nie ma powodu, aby dodawać .txtrozszerzenie do pliku tekstowego. Możesz to zrobić, ale nie ma to żadnej różnicy. Jeśli więc mimo wszystko chcesz uzyskać rozszerzenie, użyj jednego z:

xargs -I {} touch {}.txt < file
perl -ne '`touch "$_.txt"`' file
awk '{printf "" > $0".txt"}' file 
terdon
źródło
7

AWK nadaje się również do tego zadania:

testerdir:$ awk '{system("touch "$0)}' filelist

testerdir:$ ls
filelist  george  james  john  stewert

testerdir:$ awk '{system("touch "$0".txt")}' filelist                          

testerdir:$ ls
filelist  george.txt  james.txt  john.txt  stewert.txt
george    james       john       stewert

Innym sposobem, tee. Zauważ, że to podejście zostanie przerwane, jeśli linia zawiera więcej niż jeden ciąg na liście plików.

testerdir:$ echo "" | tee $(cat filelist)


testerdir:$ ls
filelist  george  james  john  stewert

Alternatywnie </dev/null tee $(cat filelist)można to również zrobić, jeśli chcesz uniknąć instalacji rurowej

cp /dev/null podejście (jak pokazałem, działa to z nazwami plików, które zawierają spacje):

testerdir:$ cat filelist | xargs -I {}  cp /dev/null  "{}"                     

testerdir:$ ls
filelist  FILE WITH SPACES  george  james  john  stewert

testerdir:$ ls FILE\ WITH\ SPACES                                              
FILE WITH SPACES
Sergiy Kolodyazhnyy
źródło
1
@kos, jeśli każda linia w pliku zawiera dokładnie jeden ciąg w linii, wówczas tworzy plik w linii. Jest efektywnie taki sam jak echo "" | tee file1 file2 file2. Ale psuje się, jeśli nazwy plików zawierają spacje.
Sergiy Kolodyazhnyy
7

Powiedzmy, że mam plik tekstowy…

Powiedzmy, że mam odpowiedź ;)

awk '{system("touch \""$0".txt\"")}' file

Wodoodporny również ze spacjami i sufiksem =)

AB
źródło