Apakah ini UUOC (penggunaan cat yang tidak berguna) untuk mengarahkan ulang satu file ke file lainnya?

36

Jika saya ingin membuat isi yang file2sesuai dengan isi file1, saya jelas bisa langsung lari cp file1 file2.

Namun, jika saya ingin melestarikan segala sesuatu tentang file2 kecuali isi-pemilik, perizinan, atribut diperpanjang, ACL, hard link, dll, dll, maka saya tidak akan ingin menjalankan cp. * Dalam hal ini saya hanya ingin celepuk yang isi file1ke dalam file2.

Sepertinya yang berikut akan melakukannya:

< file1 > file2

Tapi itu tidak berhasil. file2dipotong menjadi tidak ada dan tidak ditulis untuk. Namun,

cat < file1 > file2

tidak bekerja.

Itu mengejutkan saya bahwa versi pertama tidak berfungsi.

Apakah versi kedua UUOC? Apakah ada cara untuk melakukan ini tanpa menggunakan perintah, hanya dengan menggunakan pengalihan?

Catatan: Saya sadar bahwa UUOC lebih merupakan titik pedantic daripada anti-pola yang sebenarnya.

* Sebagai tniles09 ditemukan , cp akan sebenarnya bekerja dalam kasus ini.

Wildcard
sumber
3
Apakah < file1 > file2melakukan apa yang Anda inginkan tergantung pada shell.
Michael Homer
13
Yah, ini adalah Penggunaan yang Tidak Berguna dari <...
jwodder
2
apa itu anti-pola ?
mikeserv
6
@ jwodder - itu tidak benar. terutama ketika Anda berbicara tentang salinan. mempertimbangkan apa yang terjadi ketika file1tidak ada atau tidak dapat dibaca dan Anda membukanya dengan < sebelum > output dibuka, dan kemudian mempertimbangkan apa yang terjadi ketika Anda mengizinkan catuntuk mencoba membukanya.
mikeserv
3
@JonathanLeffler Di zsh perintah kosong dengan pengalihan dipanggil cat(secara default), pada dasarnya menjalankan perintah kedua. Lihat jawaban Stéphane Chazelas di bawah ini untuk lebih dari itu daripada cocok dalam komentar.
Michael Homer

Jawaban:

58

cat < file1 > file2bukan UUOC. Klasik, <dan >lakukan pengalihan yang sesuai dengan duplikasi file deskriptor di tingkat sistem. Duplikasi file deskriptor sendiri tidak melakukan apa-apa (well, >redirections terbuka dengan O_TRUNC, jadi untuk menjadi akurat, redirection output memang memotong file output). Jangan biarkan < >simbol membingungkan Anda. Pengalihan tidak memindahkan data — mereka menetapkan deskriptor file ke deskriptor file lainnya.

Dalam hal ini Anda membuka file1dan menetapkan deskriptor file tersebut ke deskriptor file 0( <file1== 0<file1) dan file2dan menetapkan deskriptor file tersebut ke deskriptor file 1( >file2== 1>file2).

Sekarang setelah Anda memiliki dua deskriptor file, Anda perlu proses untuk menyekop data di antara keduanya — dan itulah gunanya cat.

PSkocik
sumber
11
Mungkin hanya saya, tetapi bagian favorit saya dari jawaban ini adalah penggunaan kata "sekop". :) Sangat jelas, terima kasih.
Wildcard
1
@ Kartu Memori Saya lebih suka "memompa" daripada "sekop", tetapi masih kata yang baik. +1
Mehrdad
mengapa sekop adalah kata yang baik?
bubakazouba
1
Satu sekop tumpukan tanah, satu sekop penuh pada satu waktu, dari satu tumpukan ke yang lain saat data disalin buffer dengan buffer. Ini analogi yang bagus.
bsd
1
Dalam kalimat pertama Anda, Anda mengatakan file deskriptor sedang digandakan. Apakah mereka digandakan atau dipindahkan (seperti paragraf kedua Anda, dan perilaku fitur, tampaknya menunjukkan)?
Greg Bell
17

Bukan, karena seperti yang telah ditunjukkan orang lain, perilaku yang dipermasalahkan bergantung pada shell. Seperti yang telah Anda (OP) tunjukkan, ini agak terlalu menyolok , bahkan mungkin lucu? , semacam topik.

Namun, pada sistem GNU, premis awal Anda memiliki solusi lain yang tersedia: cp --no-preserve=all file1 file2. Coba ini, saya pikir itu akan memuaskan situasi yang Anda gambarkan (misalnya memodifikasi konten file2sambil tidak mengubah atributnya).

contoh :

$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 16 Dec 16 12:21 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Lookout, world!
    Hello, world!
$ cp --no-preserve=all fred fezzik 
$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 14 Dec 16 12:22 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Hello, world!
    Hello, world!

PEMBARUAN Sebenarnya, saya hanya memperhatikan bahwa sistem saya cpdengan sendirinya tampaknya mempertahankan atribut kecuali -aatau -pditentukan. Saya menggunakan bash shell dan GNU coreutils. Saya kira Anda belajar sesuatu yang baru setiap hari ...


Hasil pengujian (menurut Wildcard) termasuk tautan keras dan izin berbeda:

$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 file2
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the original contents of file2
$ cp file1 file2
$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 file2
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the contents of file1
$ 
tniles
sumber
Bagus. Saya menjalankan tes saya sendiri termasuk tautan keras dan izin yang berbeda dan tampaknya Anda benar.
Wildcard
Menambahkan hasil tes saya; harap kamu tidak keberatan. :) Saya tidak menguji ACL atau atribut yang diperluas tetapi mengingat bahwa nomor inode dipertahankan, saya 99% yakin itu juga.
Wildcard
Bagus ... tidak keberatan sama sekali. :-)
tniles
13

Dalam zsh, shell di mana < file1 > file2berfungsi, shell tidak memanggil cat.

Untuk baris perintah yang hanya terdiri dari pengalihan dan tanpa perintah atau penugasan, zshpanggil $NULLCMD( catsecara default) kecuali pengalihan hanya adalah yang <dalam hal ini $READNULLCMD( pagersecara default) dipanggil sebagai gantinya. (itu kecuali zshada dalam shatau cshemulasi dalam hal ini berperilaku seperti cangkang yang ditiru).

Begitu:

< file1 > file2

sebenarnya sama dengan

cat < file1 > file2

dan

< file1

sama dengan

pager < file1
Stéphane Chazelas
sumber
Sebagai catatan, sintaks ini tidak bekerja untuk ksh93
fpmurphy
8
< from > to

tidak berfungsi karena tidak ada perintah di sana; tidak ada proses. Shell membuka / membuat file dan mengatur pengalihan (artinya deskriptor file yang mereferensikan file ini ditanam sebagai 0 dan 1: input standar dan output standar). Tetapi tidak ada yang bisa dilakukan mengeksekusi loop untuk membaca dari input standar dan menulis ke output standar.

zshmembuat ini bekerja dengan mengganti perintah yang dapat dikonfigurasi pengguna dalam kasus "perintah nol" ini. Perintah tidak terlihat di baris perintah, tetapi masih ada di sana. Suatu proses dibuat untuk itu dan bekerja dengan cara yang sama. NULLCMDsecara catdefault, jadi < from > tosebenarnya berarti cat < from > to dalam zsh, kecuali NULLCMDdiatur ke sesuatu yang lain; ini adalah perintah "kucing implisit".

"Penggunaan kucing yang tidak berguna" terjadi ketika catdigunakan sebagai perantara untuk membaca dari file dan mengumpankan data ke proses lain, yang deskriptor file-nya hanya dapat dihubungkan ke file asli.

Jika catdilepas dari situasi, sehingga perintah yang tersisa masih dapat melakukan tugas yang sama, itu tidak berguna. Jika tidak dilepas, maka itu tidak berguna.

# useless, removable:
$ cat archive.tar | tar tf -    #  -->  tar tf archive.tar

# not removable (in POSIX shell):
$ cat > file
abc
[Ctrl-D]

# likewise:
STRING=$(cat file)

A catyang bisa diganti bukan hal yang sama. Misalnya alih-alih yang cat > filebisa kita gunakan vi fileuntuk membuat file. Itu tidak dihitung sebagai penghapusan cat, saat menggunakan apa pun yang tersisa untuk mencapai tugas yang sama.

Jika catadalah satu - satunya perintah dalam pipa, maka tentu saja itu tidak dapat dihapus; tidak ada pengaturan ulang apa pun yang tersisa akan melakukan pekerjaan yang setara.

Beberapa skrip shell digunakan catkarena mereka pikir itu memungkinkan mereka memindahkan operan input lebih dekat ke sisi kiri baris perintah. Namun, pengalihan bisa di mana saja di baris perintah:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing
Kaz
sumber
btw, kamu tidak harus menggunakan f -tar. tar xf -hanya tar x.
dnt
@ mikeserv Di mana dikatakan bahwa catia terlibat dalam pembuatan file? Jawaban dengan jelas mengatakan bahwa shell melakukan ini. Masalah apa > fileyang Anda maksudkan? Saya sering menggunakannya sendiri untuk memotong file yang sudah ada hingga nol panjang atau memastikan ada. Pertanyaan ini tentang mengapa < from > totidak berfungsi cat < from > to, dan UUoC, bukan "tolong beri saya alasan mengapa catbukan pengganti yang baik untuk cp".
Kaz
1
@ Dnt, taradalah pengarsipan tape . Banyak tarimplementasi masih bekerja dengan perangkat rekaman pertama secara default.
Stéphane Chazelas
1

< file1 > file2 Tampaknya tergantung pada shell, pada zsh berfungsi, pada bash tidak.

sunting: pernyataan salah dihapus

enak
sumber
cp -amempertahankan atribut file1 dan menimpa atribut file2. Berlawanan dengan perilaku yang diinginkan. Ditambah lagi, saya tidak bisa mengatakan dengan melihat halaman manual apa yang akan terjadi dengan tautan keras, tetapi saya pikir aman untuk mengatakan bahwa tautan keras file2 tidak akan disimpan.
Wildcard
Anda benar, saya tidak cukup membaca pertanyaan itu.
tastytea
1

Selain semua jawaban yang baik, Anda dapat menghindari UUOC dengan simulasi sebuah cat:

awk 1 file1 > file2   # For line-oriented text, not binaries.
dd if=file1 of=file2  # Works for binary files, too.
# many more geeky ways.

Perintah-perintah ini tidak menyalin file meta data, seperti biasa cp.

Jens
sumber
Benar, tetapi perlu disebutkan bahwa mereka tidak memiliki keunggulan dan hanya kekurangan (kinerja, keandalan) cat. Di sini Anda perlu perintah untuk mendorong data antara dua file deskriptor dan catmerupakan salah satu yang terbaik untuk itu. Lihat juga pvyang dapat digunakan splice()di Linux untuk fifos, (meskipun tidak fadvise(POSIX_FADV_SEQUENTIAL)seperti GNU cat).
Stéphane Chazelas
The ddperintah untuk file biner tampaknya baik ... atau akan catbekerja sama dengan baik untuk file biner?
Wildcard
@Wildcard catjuga berfungsi untuk file biner (Unix umumnya tidak membedakan; namun, beberapa alat secara khusus bekerja baris demi baris, seperti awk, grep, wc, ... POSIX juga mendefinisikan panjang garis minimum terbesar, jadi secara teori alat yang berorientasi garis mungkin menolak berurusan dengan saluran yang terlalu besar.)
Jens
2
@ StéphaneChazelas Jawaban ini juga dimaksudkan sebagai bahasa sederhana. Sepertinya, terlepas dari musim, beberapa orang alergi terhadap kesenangan (tidak diarahkan pada Anda; Saya menghargai keahlian shell Anda dan standar Opengroup berfungsi).
Jens
sed '' < file1 > file2;-)
Trauma Digital
0

Jika berhasil, jangan memperbaikinya.

Saya akan menggunakan

cat < file1 > file2

dan tidak memusingkan PC semantik.

krazykyngekorny
sumber