Saya ingin mem-pipe nama file ke program lain, tetapi semuanya tersedak ketika namanya mengandung spasi.
Katakanlah saya memiliki file yang dipanggil.
foo bar
Bagaimana saya bisa find
mengembalikan nama yang benar?
Jelas saya ingin:
foo\ bar
atau:
"foo bar"
EDIT : Saya tidak ingin melanjutkan xargs
, saya ingin mendapatkan string yang diformat dengan benar find
sehingga saya dapat menyalurkan string nama file secara langsung ke program lain.
-exec
bendera tersebutfind
? Anda berpotensi mengurangi kesalahan ini dan membuat perintah Anda lebih efisien dengan melakukan-exec
alih - alih mengirimnya ke perintah lain. Just my $ .02find
memformat nama file dengan baik; mereka dituliskan satu nama per baris. (Tentu saja, ini ambigu jika nama file mengandung karakter baris baru.) Jadi masalahnya adalah penerima menerima "tersedak" ketika mendapat spasi, yang berarti Anda harus memberi tahu kami apa yang menjadi penerima adalah jika Anda ingin jawaban yang bermakna .find
menawarkan opsi untuk menampilkan nama file dalam format yang sesuai untuk shell. Namun, secara umum, ekstensi-print0
GNUfind
berfungsi dengan baik untuk banyak skenario lain (juga), dan Anda harus belajar menggunakannya dalam peristiwa apa pun.ls $(command...)
tidak memberi makan daftar melaluistdin
. Ini menempatkan output$(command...)
langsung ke baris perintah. Dalam hal ini, itu adalah shell yang membaca dari c, dan itu akan menggunakan nilai saat ini$IFS
untuk memutuskan bagaimana kata-kata mencantumkan output. Secara umum, Anda lebih baik menggunakanxargs
. Anda tidak akan melihat hit kinerja.find -printf '"%p"\n'
akan menambahkan tanda kutip ganda di sekitar setiap nama yang ditemukan, tetapi tidak akan mengutip dengan benar tanda kutip ganda dalam nama file. Jika nama file Anda tidak memiliki tanda kutip ganda yang disematkan, Anda dapat mengabaikan masalah: atau menyalurkannyased 's/"/&&/g;s/^""/"/;s/""$/"/'
. Jika nama file Anda akhirnya ditangani oleh shell, Anda mungkin harus menggunakan tanda kutip tunggal, bukan tanda kutip ganda, (jika tidaksweet$HOME
akan menjadi sesuatu sepertisheet/home/you
). Dan ini masih sangat tidak kuat terhadap nama file dengan baris baru di dalamnya. Bagaimana Anda ingin mengatasinya?Jawaban:
POSIXLY:
Dengan
find
dukungan-print0
danxargs
dukungan-0
:-0
Opsi memberi tahu xargs untuk menggunakan karakter ASCII NUL alih-alih ruang untuk mengakhiri (memisahkan) nama file.Contoh:
sumber
ls $(find . -maxdepth 1 -type f -print0 | xargs -0)
saya mendapatkanls: cannot access ./foo: No such file or directory
ls: cannot access bar: No such file or directory
$(..)
tanda kutip ganda"$(..)"
find
danxargs
.Menggunakan
-print0
adalah salah satu pilihan, tetapi tidak semua program mendukung menggunakan data NullByte dipisahkan sungai, sehingga Anda akan harus menggunakanxargs
dengan-0
pilihan untuk beberapa hal, sebagai jawaban Gnouc mencatat.Sebuah alternatif akan digunakan
find
s'-exec
atau-execdir
opsi. Yang pertama dari yang berikut ini akan memberi nama filesomecommand
satu per satu, sedangkan yang kedua akan berkembang ke daftar file:Anda mungkin menemukan bahwa Anda lebih baik menggunakan globbing dalam banyak kasus. Jika Anda memiliki shell modern (bash 4+, zsh, ksh), Anda bisa mendapatkan globbing rekursif dengan
globstar
(**
). Dalam bash, Anda harus mengatur ini:Saya memiliki garis yang mengatakan
shopt -s globstar extglob
di .bashrc saya, jadi ini selalu diaktifkan untuk saya (dan juga gumpalan diperpanjang, yang juga berguna).Jika Anda tidak ingin rekursif, jelas gunakan
./*.txt
saja, untuk menggunakan setiap * .txt di direktori kerja.find
memiliki beberapa kemampuan pencarian berbutir halus yang sangat berguna, dan wajib untuk puluhan ribu file (saat itu Anda akan menemukan argumen dalam jumlah maksimum shell), tetapi untuk penggunaan sehari-hari seringkali tidak diperlukan.sumber
Secara pribadi, saya akan menggunakan
-exec
tindakan temukan untuk memecahkan masalah semacam ini. Atau, jika perluxargs
,, yang memungkinkan eksekusi paralel.Namun, ada cara
find
untuk menghasilkan daftar nama file yang bisa dibaca oleh bash. Tidak mengherankan, ia menggunakan-exec
danbash
, khususnya ekstensi untukprintf
perintah:Namun, sementara itu akan mencetak dengan benar kata-kata yang keluar dengan shell, itu tidak akan dapat digunakan dengan
$(...)
, karena$(...)
tidak menafsirkan kutipan atau lolos. (Hasil dari$(...)
tunduk pada pemisahan kata dan perluasan pathname, kecuali dikelilingi oleh tanda kutip.) Jadi yang berikut ini tidak akan melakukan apa yang Anda inginkan:Yang harus Anda lakukan adalah:
(Perhatikan bahwa saya tidak melakukan upaya nyata untuk menguji keburukan di atas.)
Namun, Anda sebaiknya melakukannya:
sumber
ls
skenario cukup menangkap kasus penggunaan OP, tapi ini hanya spekulasi, karena kita belum ditunjukkan apa yang sebenarnya dia coba capai. Solusi ini sebenarnya bekerja dengan sangat baik; Saya mendapatkan output yang saya (samar-samar) diharapkan untuk semua nama file lucu yang saya coba, termasuktouch "$(tr a-z '\001-\026' <<<'the quick brown fox jumped over the lazy dogs')"
eval
adalah Anda belum harus meneruskannyaeval
; Anda bisa menyimpannya di parameter dan menggunakannya nanti, mungkin beberapa kali dengan perintah yang berbeda. Namun, OP tidak memberikan indikasi bahwa itu adalah use case (dan jika ya, mungkin lebih baik untuk memasukkan nama file ke dalam array, meskipun itu juga sulit.)akan memberi Anda file dan direktori berisi spasi
akan memberi Anda file berisi spasi
akan memberi Anda direktori berisi spasi
sumber
sumber