Salin daftar file

35

Saya memiliki daftar file yang dipisahkan oleh spasi dalam file list.txt. Saya ingin menyalinnya ke folder baru.

Saya mencoba melakukan:

cp `cat list.txt` new_folder

tapi itu tidak berhasil.

Bagaimana Anda melakukan ini?

Memperbarui:

Terima kasih atas semua jawaban Anda yang sangat menarik. Saya tidak banyak meminta :)

Setelah mencoba solusi di atas untuk yang kedua kalinya, tampaknya cpbantuan penggunaan cetak karena folder new_folderbelum ada! Maaf, ini kelihatannya merupakan kesalahan bodoh ... Ketika saya membuat folder sebelumnya, itu berfungsi.

Namun, saya telah belajar banyak dari semua jawaban dan solusi Anda, terima kasih atas waktu yang Anda berikan untuk menulisnya.

Klaus
sumber
Biarkan saya jelaskan satu hal: daftar memiliki semua nama file pada satu baris, hanya dipisahkan oleh spasi? Atau apakah masing-masing nama di baris yang berbeda?
Telemakus
Semua dalam satu jeruk nipis, dipisahkan oleh spasi. Solusi Doug berhasil :) Terima kasih atas jawabannya.
Klaus
Itu lucu ... Saya menguji solusi saya dengan garis di mana masing-masing nama berada di jalur yang terpisah.
Doug Harris
"tidak berhasil" tidak terlalu berarti. Bagaimana tepatnya itu tidak berhasil. Ini bekerja dengan baik untuk saya.
Dijeda sampai pemberitahuan lebih lanjut.
Maaf: ini menunjukkan bantuan penggunaan cp. Lihat pembaruan saya di atas.
Klaus

Jawaban:

34

Coba gunakan xargs:

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

Memperbarui:

Saya melakukan ini pada OS X yang memiliki versi berbeda dari versi GNU / Linux. Yang xargsberasal dari GNU findutils tidak memiliki -Jtetapi memiliki -Iyang serupa (seperti yang ditunjukkan oleh Dennis Williamson dalam komentar). Versi OS X dari xargs memiliki keduanya -Idan -Jyang memiliki perilaku yang sedikit berbeda - keduanya akan berfungsi untuk pertanyaan asli ini.

$ 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
sumber
3
Saya xargstidak memilikinya -Jmemiliki -Iyang tampaknya melakukan hal yang sama. Versi xargsapa dan OS / distribusi apa yang Anda miliki?
Dijeda sampai pemberitahuan lebih lanjut.
Saya menguji ini pada Mac OS X 10.6 (alias macan tutul salju), jadi itu versi xargs apa pun yang disertakan dengan OS. Menjalankan xargs --versionmengembalikan pesan kesalahan penggunaan. Kemungkinan versi xargs BSD. Penggunaan -Idan -Jagak berbeda. Saya akan memperbarui jawaban saya dengan contoh yang diformat dengan baik.
Doug Harris
Yap, saya sedang bekerja dengan Mac OSX 10.6. Terima kasih atas persiapan -Jdan -I:)
Klaus
Itu tip yang baik untuk menggunakan gema untuk memeriksa perintah Anda sebelum Anda menjalankannya.
Liam
1
Menggunakan perintah yang sama di atas dengan perubahan yang diperlukan saja, bagaimana cara menyalin file bersama dengan membuat direktori dan subdirs mereka, dipisahkan oleh slash?
Vicky Dev
54

Tidak perlu catsama sekali:

xargs -a list.txt cp -t new_folder

Atau menggunakan opsi panjang:

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

Berikut ini beberapa versi shell. Perhatikan bahwa beberapa variabel tidak dikutip atau forloop digunakan secara khusus karena OP menetapkan bahwa nama file dibatasi oleh ruang. Beberapa teknik ini tidak akan berfungsi untuk input nama file per baris di mana nama file berisi ruang putih.

Pesta:

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

atau

cp $(<list.txt) new_folder

sh (atau Bash):

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

atau

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

atau

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

atau

# meow
cp $(cat list.txt) new_folder
Dijeda sampai pemberitahuan lebih lanjut.
sumber
pertanyaan noob: mengapa -tdiperlukan xargs -a list.txt cp -t new_folder?
Yibo Yang
1
@YiboYang: -tOpsi untuk cp. Ini menyalin semua argumen sumber ke direktori target yang ditentukan. Di sini, ini memungkinkan target untuk ditentukan sebelum sumber yang ditambahkan oleh xargsperintah.
Dijeda sampai pemberitahuan lebih lanjut.
Ini berguna tetapi bagaimana jika list.txt berisi file campuran dan path folder? Dalam hal ini perintah tidak berfungsi dengan baik. Ini melaporkan "menghilangkan direktori ..." dan jika -R ditentukan untuk perintah cp maka kesalahan "bukan direktori" dilaporkan segera setelah file pertama dalam daftar ditemukan.
Bemipefe
7

Saya punya jawaban yang memalukan di sini sebelumnya, tetapi jawaban Denis mengingatkan saya bahwa saya melewatkan hal yang paling mendasar. Jadi, saya menghapus jawaban asli saya. Tetapi karena tidak ada yang mengatakan hal yang sangat mendasar ini, saya pikir ada baiknya untuk meletakkannya di sini.

Pertanyaan aslinya adalah "Saya memiliki file teks dengan daftar nama file yang dipisahkan oleh ruang. Bagaimana saya bisa menyalinnya ke satu direktori target." Pada awalnya ini mungkin tampak rumit atau rumit, karena Anda berpikir Anda harus mengekstraksi item dari file dengan cara tertentu. Namun, ketika shell memproses sebuah baris perintah, hal pertama yang dilakukannya adalah memisahkan daftar argumen menjadi token dan (di sini sedikit yang tidak ada yang mengatakan langsung) spasi token yang terpisah . (Newlines juga memisahkan token yang mengapa pengujian Doug Harris dengan daftar yang dipisahkan dengan baris baru memiliki hasil yang sama.) Yaitu, shell mengharapkan dan sudah dapat menangani daftar yang dipisahkan oleh ruang.

Jadi yang perlu Anda lakukan di sini adalah meletakkan daftar yang dipisahkan oleh ruang (yang sudah Anda miliki) ke tempat yang tepat dalam perintah Anda. Perintah Anda adalah beberapa variasi dalam hal ini:

cp file1 file2 file3...file# target

Satu-satunya kerutan adalah Anda ingin mendapatkan daftar file 1 hingga # dari file teks Anda.

Seperti yang ditunjukkan oleh Dennis dalam komentarnya, upaya awal Anda ( cpcat list.txt new_folder) seharusnya sudah berhasil. Mengapa? Karena perintah internal cat list.txtdiproses terlebih dahulu oleh shell dan berkembang menjadi file1 file2 file3...file#, yang persis seperti yang diharapkan dan diinginkan shell pada bagian perintah itu. Jika tidak berhasil maka (1) Anda salah ketik atau (2) nama file Anda entah bagaimana aneh (mereka memiliki spasi atau karakter tidak biasa lainnya).

Alasan semua jawaban Dennis bekerja adalah karena mereka menyediakan daftar file yang diperlukan untuk cpdikerjakan, menempatkan daftar itu di tempat yang termasuk dalam seluruh perintah. Sekali lagi, perintah itu sendiri adalah struktur ini:

cp list-of-files target_directory

Sangat mudah untuk melihat bagaimana semua ini menyatu dalam versi ini:

cp $(<list.txt) new_folder

$()menyebabkan shell menjalankan perintah di dalam tanda kurung dan kemudian mengganti outputnya pada titik tersebut di baris yang lebih besar. Kemudian shell menjalankan garis secara keseluruhan. Omong-omong, $()adalah versi yang lebih modern dari apa yang sudah Anda lakukan dengan backticks (`). Berikutnya: <adalah operator pengalihan file. Ia memberi tahu shell untuk membuang konten list.txtke input standar. Karena $()bit diproses terlebih dahulu, inilah yang terjadi secara bertahap:

  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

Jelas langkah 2 hanyalah cpperintah normal yang Anda inginkan.

Saya menyadari bahwa saya sering mengalahkan kuda ini (mungkin sangat mati), tetapi saya pikir ini layak dilakukan. Memahami persis bagaimana shell memproses suatu perintah dapat membantu Anda untuk menulisnya dengan lebih baik dan menyederhanakan banyak hal. Ini juga akan menunjukkan kepada Anda di mana masalah cenderung bersembunyi. Dalam kasus ini, misalnya, pertanyaan pertama saya kepada Anda seharusnya tentang nama file lucu atau kemungkinan kesalahan ketik. Tidak diperlukan akrobat.

Telemakus
sumber
@ Klaus Terima kasih. Sejujurnya, saya sebagian besar kesal pada diri saya sendiri setelah membaca jawaban Dennis dan menyadari bahwa saya melewatkan bagian kunci dari masalah sepenuhnya. Solusi yang Anda suka dari sana juga.
Telemakus
Ini adalah jawaban yang sangat lama, tetapi jika Anda perlu membuat kembali struktur folder, Anda perlu --parentsbenderanya. Anda dapat membuatnya dengan kata lain -vuntuk catatan apa yang telah disalin. Jika Anda ingin mempertahankan izin, Anda memerlukan tanda -aatau -p. Yaitu cp --parents -av $(<list.txt) new_folder,. Ini semua dengan asumsi daftar file Anda benar-benar semua file, kalau tidak, Anda mungkin juga perlu -rmenandai untuk muncul kembali.
dhaupin
@ Dhupin Sebenarnya, OP menyatakan bahwa ia menggunakan MacOS. Jadi untuk apa nilainya, --parentsbendera itu tidak ada di sana. Versi mereka (yang diturunkan dari BSD) cphanya menyediakan opsi pendek, bukan opsi panjang gaya GNU. Untuk gaya BSD cp, flag untuk salinan rekursif adalah huruf besar -R, bukan huruf kecil.
Telemakus