Ada beberapa masalah.
>>
dalam perintah pertama Anda akan ditafsirkan oleh shell Anda saat ini sebagai pengalihan ke file yang benar-benar bernama {}
, kecuali itu dikutip.
*.ovpn
dapat diperluas dengan shell globbing sebelum find
dijalankan. Ini akan terjadi jika Anda memiliki setidaknya satu objek di direktori saat ini yang cocok dengan pola. Anda ingin mengutip ini. Bandingkan pertanyaan ini .
Anda mendapatkan Can't open echo
karena memang Anda mengatakan sh
untuk membuka echo
. Untuk menjalankan perintah yang Anda butuhkan sh -c
.
find
tanpa menentukan jalurnya tidak portabel (bandingkan pertanyaan ini ). Meskipun Anda bisa lolos dengan ini, saya menyebutkan masalah ini untuk membuat jawaban lebih bermanfaat bagi pengguna lain.
Ini adalah versi peningkatan dari perintah pertama Anda yang agak berfungsi (jangan jalankan, terus membaca):
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "{}"' \;
Perhatikan saya harus menggandakan penawaran {}
di dalam kutipan tunggal. Kutipan ganda ini "dilihat" oleh sh
dan membuat nama file dengan spasi dll berfungsi sebagai target pengalihan. Tanpa penawaran Anda mungkin berakhir dengan echo "line to append" >> foo bar.ovpn
yang setara dengan echo "line to append" bar.ovpn >> foo
. Mengutip membuatnya sebagai echo "line to append" >> "foo bar.ovpn"
gantinya.
Sayangnya nama file yang mengandung "
akan memecah sintaks ini.
Cara yang tepat untuk lulus {}
untuk sh
tidak untuk memasukkannya ke dalam perintah string tetapi untuk lulus isinya sebagai argumen yang terpisah:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$0"' {} \;
$0
di dalam string perintah meluas ke argumen pertama yang kita sh
dapatkan -c '…'
. Sekarang bahkan "
dalam nama file tidak akan merusak sintaks.
Biasanya (seperti dalam naskah) untuk merujuk pada argumen pertama yang Anda gunakan $1
. Inilah alasan beberapa pengguna lebih suka menggunakan argumen dummy $0
, seperti ini:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' dummy {} \;
Jika itu skrip, $0
akan diperluas ke namanya. Itu sebabnya tidak jarang melihat ini dummy
benar-benar menjadi sh
(atau bash
, jika seseorang memanggil bash -c …
dll):
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' sh {} \;
Tapi tunggu! find
panggilan terpisah sh
untuk setiap file tunggal. Saya tidak berharap Anda memiliki ribuan .ovpn
file, tetapi secara umum Anda mungkin ingin memproses banyak file tanpa memunculkan proses yang tidak perlu. Kami dapat mengoptimalkan pendekatan dengan tee -a
yang dapat menulis ke banyak file sebagai satu proses:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" | tee -a "$@" >/dev/null' sh {} +
Perhatikan {} +
, ini melewati beberapa jalur sekaligus. Di dalam perintah dieksekusi oleh sh -c
kita mengambil mereka dengan "$@"
, yang mengembang ke "$1" "$2" "$3" …
. Dalam hal ini argumen dummy yang terisi (tidak digunakan) $0
adalah suatu keharusan.
Secara umum ada juga masalah ini: Mengapa printf
lebih baik daripada echo
? Namun dalam hal ini Anda menggunakan echo
tanpa opsi dan string yang didapat bersifat statis, jadi seharusnya tidak masalah.