Skopiuj listę plików

27

Mam listę plików oddzielonych spacjami w pliku list.txt. Chciałbym skopiować je do nowego folderu.

Próbowałem to zrobić:

cp `cat list.txt` new_folder

ale to nie zadziałało.

Jak byś to zrobił?

Aktualizacja:

Dziękuję za wszystkie bardzo interesujące odpowiedzi. Nie prosiłem o to za dużo :)

Po wypróbowaniu rozwiązania powyżej po raz drugi wydaje się, że cp wydrukował pomoc dotyczącą użytkowania, ponieważ folder new_folder jeszcze nie istniał! Niestety, wydaje się, że to głupi błąd ... Kiedy tworzę folder wcześniej, działa.

Nauczyłem się jednak wiele ze wszystkich odpowiedzi i rozwiązań, dziękuję za poświęcony czas na ich napisanie.

Klaus
źródło
Pozwólcie, że wyjaśnię jedną rzecz: lista ma wszystkie nazwy plików w jednym wierszu, oddzielone tylko spacją? A może każda z nich ma osobną linię?
Telemachus
Wszystko w jednym wapnie, oddzielone spacją. Rozwiązanie Douga zadziałało :) Dziękuję za odpowiedź.
Klaus
To zabawne ... Przetestowałem moje rozwiązanie linią, w której każda nazwa była w osobnej linii.
Doug Harris
„to nie zadziałało” nie jest zbyt znaczące. Dokładnie w jaki sposób czy to nie zadziałało. To działa dobrze dla mnie.
Dennis Williamson
Przepraszamy: pokazała pomoc w używaniu cp. Zobacz moją aktualizację powyżej.
Klaus

Odpowiedzi:

30

Spróbuj użyć xargs:

cat list.txt | xargs -J % cp % new_folder

Aktualizacja:

Zrobiłem to na OS X, który ma inną wersję niż wersje GNU / Linux. The xargs który pochodzi z GNU findutils nie ma -J ale tak jest -I co jest podobne (jak zauważył Dennis Williamson w komentarzu). Wersja xargs systemu OS X ma obie wersje -I i -J które mają nieco inne zachowania - albo będą działać dla tego oryginalnego pytania.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
Doug Harris
źródło
3
Mój xargs nie ma -J to ma -I który wydaje się robić to samo. Jaka wersja xargs a jaki masz system operacyjny / dystrybucję?
Dennis Williamson
Przetestowałem to na Mac OS X 10.6 (aka snow leopard), więc jest to każda wersja xargs dostarczana z systemem operacyjnym. Bieganie xargs --version zwraca komunikat o błędzie użycia. Prawdopodobnie jest to wersja xargs BSD. Sposób użycia -I i -J są nieco inne. Zaktualizuję moją odpowiedź ładnie sformatowanymi przykładami.
Doug Harris
Tak, pracuję z Mac OSX 10.6. Dziękuję za dokładność -J i -I :)
Klaus
To dobra wskazówka, aby użyć echa do sprawdzenia poleceń przed ich uruchomieniem.
Liam
Używając tego samego polecenia z koniecznymi zmianami, jak mogę skopiować pliki wraz z tworzeniem ich katalogów i podkatalogów, w których się znajdują, oddzielone ukośnikiem?
Vicky Dev
44

Nie ma potrzeby cat w ogóle:

xargs -a list.txt cp -t new_folder

Lub używając długich opcji:

xargs --arg-file=list.txt cp --target-directory=new_folder

Oto kilka wersji powłoki:

Grzmotnąć:

for file in $(<list.txt); do cp "$file" new_folder; done

lub

cp $(<list.txt) new_folder

sh (lub Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

lub

# none here either
while read -r line; do cp $line new_folder; done < list.txt

lub

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

lub

# meow
cp $(cat list.txt) new_folder
Dennis Williamson
źródło
pytanie noob: dlaczego jest -t potrzebne w xargs -a list.txt cp -t new_folder?
Yibo Yang
1
@YiboYang: The -t jest opcja cp. Kopiuje wszystkie argumenty źródłowe do określonego katalogu docelowego. Tutaj pozwala na określenie celu przed źródłem dodanym przez xargs dowództwo.
Dennis Williamson
Jest to przydatne, ale co, jeśli list.txt zawiera mieszane ścieżki plików i folderów? W takim przypadku polecenie nie działa poprawnie. Zgłasza „pomijanie katalogu ...” i jeśli -R jest określone dla komendy cp, to błąd „nie jest katalogiem” jest zgłaszany, gdy tylko napotkany zostanie pierwszy plik na liście.
Bemipefe
7

Wcześniej otrzymałem wstydliwą odpowiedź, ale Odpowiedź Denisa przypomniałem mi, że przegapiłem najbardziej podstawową rzecz. Więc usunąłem moją oryginalną odpowiedź. Ale ponieważ nikt nie ma powiedziany ta bardzo podstawowa rzecz, myślę, że warto ją tutaj umieścić.

Pierwotne pytanie brzmi: „Mam plik tekstowy z listą nazw plików rozdzielonych spacjami. Jak mogę skopiować je do jednego katalogu docelowego”. Na początku może się to wydawać trudne lub skomplikowane, ponieważ uważasz, że musisz w jakiś sposób wyodrębnić elementy z pliku w określony sposób. Jednak gdy powłoka przetwarza wiersz poleceń, pierwszą rzeczą, którą robi, jest rozdziel listę argumentów na tokeny i (tu jest coś, czego nikt nie powiedział wprost) spacje oddzielne żetony . (Newlines również oddzielają tokeny, dlatego test Douga Harrisa z rozdzieloną listą linii miał taki sam wynik.) Oznacza to, że powłoka oczekuje i może już obsługiwać listę oddzieloną spacjami.

Wszystko, co musisz tutaj zrobić, to umieścić rozdzieloną spacjami listę (którą już masz) we właściwym miejscu w swoim poleceniu. Twoje polecenie to pewna odmiana tego:

cp file1 file2 file3...file# target

Jedyną zmarszczką jest to, że chcesz pobrać listę plików 1 do # z pliku tekstowego.

Jak podkreśla Dennis w swoim komentarzu, twoja oryginalna próba ( cp cat list.txt new_folder ) powinien już działać. Czemu? Ponieważ polecenie wewnętrzne cat list.txt jest przetwarzany najpierw przez powłokę i rozwija się w file1 file2 file3...file#, co jest dokładnie tym, czego powłoka oczekuje i chce w tej części polecenia. Jeśli to nie zadziałało, albo (1) miałeś literówkę, albo (2) twoje nazwy plików były w jakiś sposób dziwne (miały spacje lub inne niezwykłe znaki).

Powodem, dla którego wszystkie odpowiedzi Dennisa działają, jest po prostu dostarczenie niezbędnej listy plików cp pracować nad umieszczeniem tej listy tam, gdzie należy do całego polecenia. Ponownie samo polecenie ma taką strukturę:

cp list-of-files target_directory

Łatwo jest zobaczyć, jak to wszystko łączy się w tej wersji:

cp $(<list.txt) new_folder

$() powoduje, że powłoka uruchamia polecenie wewnątrz nawiasów, a następnie zastępuje jego wyjście w tym punkcie większej linii. Następnie powłoka uruchamia linię jako całość. Tak poza tym, $() jest bardziej nowoczesną wersją tego, co robiłeś już z backticks (`). Kolejny: < jest operatorem przekierowania plików. Mówi powłoce, aby zrzucił zawartość list.txt na standardowe wejście. Od $() bit jest przetwarzany najpierw, oto co dzieje się etapami:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Oczywiście krok 2 jest po prostu normalny cp rozkaz, który chciałeś.

Zdaję sobie sprawę, że często pokonuję tego (być może bardzo martwego) konia, ale myślę, że warto to robić. Zrozumienie dokładnie w jaki sposób powłoka przetwarza polecenie może pomóc ci lepiej napisać i uprościć. Pokaże również, gdzie mogą się ukrywać problemy. W tym przypadku na przykład moje pierwsze pytanie powinno dotyczyć zabawnych nazw plików lub literówki. Żadne akrobacje nie były konieczne.

Telemachus
źródło
@Klaus Jesteś bardzo mile widziany. Szczerze mówiąc, byłem poirytowany głównie po przeczytaniu odpowiedzi Dennisa i zdaniu sobie sprawy, że całkowicie pominąłem kluczową część problemu. Rozwiązanie, które lubisz, jest również stamtąd.
Telemachus
To bardzo stara odpowiedź, ale jeśli chcesz ponownie utworzyć strukturę folderów, potrzebujesz --parents flaga. Możesz sprawić, że będzie gadatliwy -v dla zapisu tego, co zostało skopiowane. Jeśli chcesz zachować uprawnienia, potrzebujesz -a lub -p flaga. To znaczy, cp --parents -av $(<list.txt) new_folder. To wszystko zakłada, że ​​twoja lista plików to w rzeczywistości wszystkie pliki, w przeciwnym razie możesz również potrzebować -r flaga do powtórzenia.
dhaupin
@dhaupin Właściwie OP stwierdza, że ​​był na macOS. Więc na co to jest warte --parents flaga tam nie istnieje. Ich (pochodząca z BSD) wersja cp udostępnia tylko krótkie opcje, a nie długie opcje w stylu GNU. Dla stylu BSD cp, flaga dla kopii rekurencyjnej jest wielka -R, nie małe litery.
Telemachus