Dalam skrip yang saya gunakan find
untuk mengumpulkan beberapa file di direktori saat ini, seperti pada
$ find . -name "*.h"
./foo.h
Sekarang saya ingin hanya output foo.h
, tanpa ./
awalan. Saya pikir string kosong ""
menunjukkan direktori saat ini dalam perintah shell. Tapi ini memberi:
$ find "" -name "*.h"
find: ftsopen: No such file or directory
Jadi saya salah. Sekarang pertanyaan saya adalah kapan / bagaimana / di mana / .. apakah sebuah "string kosong (?)" Menunjukkan perintah saat ini dalam perintah yang mengharapkan nama file atau nama path? Apakah ada penjelasan yang rapi dan mencerahkan?
Pertanyaan sampingannya adalah apakah temuan nitpicking di atas dapat diselesaikan dengan mudah, tanpa manipulasi string ala ${parameter#word}
atau cut
atau sed
?
find
memiliki parameter -printf untuk memanipulasi bagaimana hasil ditampilkan.find . -name '*.h' -printf '%P\n'
akan menghapus./
awalan. Lihat apafind . -name '*.h' -print
.-printf
opsi. FWIW,strings
pada temuan saya memberi@(#)PROGRAM:find PROJECT:shell_cmds-175
?!?Jawaban:
Sebuah waktu yang lama lalu (di edisi ke-7 , 32V , 4.2BSD , 4.3BSD ), pada tingkat sistem-panggilan nol-panjang pathname dilambangkan direktori kerja saat ini (saat digunakan untuk pencarian; itu dianulir ketika mencoba untuk membuat atau menghapus suatu file atau direktori). Dalam Sistem III , itu adalah kesalahan untuk menggunakan nama path panjang nol dalam semua keadaan, dan standar POSIX mengatakan ini tentang resolusi pathname:
sumber
dir/
sebagian besar sama dengandir/.
Kamu bisa menggunakan:
Perhatikan bahwa file dalam direktori saat ini yang namanya dimulai dengan
.
akan dihilangkan, dan file yang namanya dimulai dengan-
akan ditafsirkan sebagai opsi olehfind
dan menyebabkan kekacauan, jadi ini bukan setara dengan umumfind . …
.Tidak adanya string yang diakhiri dengan "
/
" sebagai bagian dari nama file menyiratkan direktori saat ini, tetapi itu tidak berarti direktori saat ini dilambangkan dengan string kosong (yang bisa dibilang tidak sama dengan tidak adanya string, meskipun mungkin terlihat sama saat dicetak).sumber
Secara umum, string kosong tidak menunjukkan direktori saat ini, baik untuk perintah shell maupun panggilan sistem. Itu terjadi pada beberapa sistem lama, tetapi tidak pada sistem yang sesuai dengan POSIX .
Kadang-kadang Anda akan menemukan program yang menggunakan direktori saat ini ketika Anda melewatkan string kosong dan program mengharapkan nama direktori. Ini kadang-kadang disengaja, dan kadang-kadang efek samping dari prepending path absolut direktori saat ini ketika string yang diberikan tidak dimulai dengan slash.
Hal terbaik untuk Anda adalah meninggalkan
./
. Tidak ada salahnya.Jika daftar file untuk
Perhatikan bahwa ini mangles beberapa nama file yang mengandung baris baru. Ini biasanya bukan masalah untuk konsumsi manusia, dan output dari
find
tidak cocok untuk konsumsi program karena ambigu. Jika Anda menggunakan-print0
, yang cocok untuk konsumsi program, Anda mungkin tidak peduli dengan./
awalannya.Anda dapat menggunakan
find * …
sebagai gantinyafind . …
, tetapi perhatikan bahwafind *
memiliki sejumlah cacat yang membuatnya tidak cocok secara umum:.
dihilangkan..
atau ..`) dihilangkan.-
(atau file bernama!
atau(
...), itu akan ditafsirkan sebagai opsi atau predikat olehfind
.Poin pertama tidak masalah jika filter Anda mengecualikan direktori saat ini. Untuk poin kedua, Anda dapat menggunakan pola
..?* .[!.]* *
untuk mencocokkan semua file di direktori saat ini, tetapi Anda harus memeriksa apakah setiap pola cocok dengan setidaknya satu file dan menghilangkannya jika tidak. Ini mungkin tetapi sangat rumit. Poin terakhir adalah stopper. Jadifind *
mungkin cocok untuk penggunaan baris perintah quickie, tetapi jangan menggunakannya dalam skrip.Pendekatan alternatif adalah dengan menggunakan fasilitas globbing rekursif shell, misalnya
Ini perlu diaktifkan oleh
shopt -s globstar
di bash dan olehset -o globstar
di ksh93, dan tidak ada di shell POSIX dasar seperti dasbor. File dot tidak akan dilalui secara default; untuk memasukkannya, pertama-tama buat globbing jangan abaikan file dot denganshopt -s dotglob
di bash atauFIGNORE='@(.|..)'
di ksh93. Juga, jika tidak ada kecocokan, maka perintah ini mencetak pola; jalankanshopt -s nullglob
bash untuk mencetak baris kosong, dan gunakan pola~(N)**/*.h
dalam ksh.Di zsh, globbing rekursif diaktifkan secara default. Gunakan kualifikasi glob
D
untuk memasukkan file titik danN
untuk mencetak baris kosong jika tidak ada yang cocok (secara default, zsh melempar kesalahan jika suatu pola tidak cocok dengan file apa pun). Anda dapat menggunakanprintf
seperti di atas atausumber
find *
saya baru, dan beberapa menakutkan !!Saya tidak dapat memikirkan contoh di mana string kosong menunjukkan direktori saat ini
.
. Anda mungkin berpikir tentang doals
, tetapi itu karenals
menganggap direktori saat ini jika tidak ada parameter yang diberikan, dan faktanya itu tidak akan mengambil string kosong:sumber
PATH
komponen.Ada berbagai trik yang dapat Anda gunakan untuk mendapatkan hasil find tanpa yang memimpin
./
:Gunakan
-printf
opsi temukan dan katakan untuk hanya mencetak%f
. Lihatman find
:Sebagai contoh:
Parsing hasilnya:
@ Trik Anthon
Adapun pertanyaan Anda yang lain, string kosong tidak pernah menunjukkan direktori saat ini. Hanya saja berbagai program menggunakan direktori saat ini sebagai default sehingga ketika Anda menjalankannya tanpa argumen, dijalankan di direktori saat ini.
sumber
find
. Atau gunakan%P
untuk hanya mengupas./
find * -name '*.h'
akan menemukanfoo/.bar.h
, tetapi tidak.bar.h
di direktori saat ini.Jika file berada di direktori saat ini Anda bisa menggunakan
ls
:Jika Anda ingin file dalam subdirektori juga dan hanya perlu nama file Anda bisa melakukan sesuatu seperti:
Ada perintah yang akan mendapatkan tidak adanya string sebagai direktori saat ini, tetapi pada dasarnya karena mereka akan mendapatkan direktori saat ini sebagai default jika tidak ada yang dimasukkan. The
.
selalu menyatakan dir saat ini (dan..
direktori induk)sumber
find
solusi Anda menghapus semua komponen direktori