Masalah saya (dalam skrip dengan #!/bin/sh
) adalah sebagai berikut: Saya mencoba untuk checksum semua file dalam direktori untuk keperluan arsip. File checksum (dalam kasus saya sh1) dengan semua nama file harus berada di direktori yang sama. Katakanlah kita memiliki direktori ~/test
dengan file f1
dan f2
:.
mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2
Sekarang menghitung checksum dengan
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum
tidak persis apa yang saya inginkan, itu daftar semua file dari direktori saat ini saja dan menghitung jumlah sha1 (maxdepth dapat diubah kemudian). Output pada STDOUT adalah:
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
Sayangnya, ketika mencoba menyimpan ini ke file dengan
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1
file yang dihasilkan menampilkan checksum untuk dirinya sendiri:
da39a3ee5e6b4b0d3255bfef95601890afd80709 sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
dan karena itu gagal di kemudian hari shasum --check
, karena masalah nyata modifikasi file tambahan saat menyimpan jumlah terakhir.
Saya melihat sekeliling dan dengan menggunakan -p
flag untuk xargs
, saya menemukan bahwa entah bagaimana ia membuat file output bahkan sebelum mengeksekusi perintah find, oleh karena itu file tambahan ditemukan dan akan checksummed ...
Saya tahu bahwa sebagai solusi saya dapat menyimpan checksum ke lokasi lain (direktori temp via mktemp
) atau mengecualikannya di find khusus, tetapi saya ingin memahami mengapa berperilaku seperti itu - yang menurut saya tidak berguna, misalnya jika perintah pertama akan memeriksa apakah file output sudah ada di disk, itu tidak akan pernah mendapatkan jawaban yang benar ...
xargs
, itu adalah shell itu sendiri yang membuat file ini, karena sebelum perintah apa pun dijalankan terlebih dahulu shell mengarahkan ulang semua input, output dan pipa, sehingga ketikafind
mulai file output sudah ada. Gunakan-exec
sebagai gantinya:find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
sh
doa diperlukan. Perhatikan bahwa Anda perlu argumen$0
sebelumnya{}
.tee
telah menghilang? Saya mencobanya dan berfungsi dengan baik, saya juga menekan STDOUT dengan menambahkan1>/dev/null
. Apakah ada yang salah dengan jawabannya atau itu bug?Jawaban:
Anda dapat mencegah mencapai file
xargs
menggunakan:Untuk mencegah masalah dengan nama file yang memiliki baris kosong atau baris baru atau kutipan atau garis miring terbalik, saya akan menggunakan:
sebagai gantinya.
The
--
adalah untuk menghindari masalah dengan nama file yang dimulai dengan-
. Namun itu tidak akan membantu untuk file yang dipanggil-
. Seandainya Anda menggunakan-print0
alih-alih-printf '%P\0'
, Anda tidak akan membutuhkan--
dan tidak akan memiliki masalah dengan-
file tersebut.sumber
basename
mendapatkan nama file sums.sha1 dari path lengkap yang diberikan (ini tidak termasuk dalam pertanyaan, tetapi mungkin membantu orang lain).Karena Anda menggunakan
-maxdepth 1
, saya menganggap Anda tidak ingin rekursi. Jika demikian, lakukan saja di shell sebagai gantinya:Untuk melewati direktori, Anda dapat melakukan:
Jika Anda memang membutuhkan rekursi dan menggunakan
bash
, lakukan:Perhatikan bahwa semua pendekatan ini bermanfaat untuk mengerjakan nama file yang sewenang-wenang, termasuk yang memiliki spasi, baris baru atau apa pun.
sumber
sums.sha1
sudah ada (dari lari sebelumnya) solusi Anda akan memasukkannya.sh
, tetapi jawaban Anda mungkin membantu orang lain.dengan
zsh
:Glob akan diperluas sebelum pengalihan dilakukan, sehingga
sums.sha1
tidak akan dimasukkan jika tidak ada di tempat pertama.D
adalah memasukkan dot-file (file tersembunyi) seperti biasafind
..
adalah memilih hanya file biasa (seperti milik Anda-type f
).Untuk mengecualikan
sums.sha1
tetap jika itu ada di tempat pertama:Perhatikan bahwa mereka menjalankan satu perintah shasum, sehingga Anda mungkin akhirnya melihat kesalahan "Daftar Arg terlalu panjang" jika daftar itu besar. Untuk mengatasinya:
Saya akan merekomendasikan menggunakan
./*
daripada*
menghindari potensi masalah dengan file yang disebut-
.sumber
Sebagai jawaban lain sudah menyatakan masalahnya adalah bahwa shell membuka dan membuat
sums.sha1
file, sebelum menjalankan pipa Anda. Anda dapat menggunakan programsponge
yang merupakan bagian darimoreutils
paket banyak distribusi. Berbeda dengan pengalihan shellsponge
akan menunggu sampai semuanya diterima, sebelum membuka file. Biasanya digunakan ketika Anda ingin menulis file yang Anda baca di pipa yang sama.Dalam kasus Anda digunakan seperti ini:
sumber
Sebagai alternatif dari find / xargs dll, Anda mungkin ingin sha1deep. Mungkin dalam paket yang berbeda - di kotak saya itu datang dalam paket md5deep.
Seperti orang lain mengatakan sums.sha1 dibuat oleh shell bahkan sebelum find dimulai. Trik dengan
! -name sums.sha1
untukfind
akan bekerja, juga akansumber