Untuk tugas saya diminta untuk secara cerdik menulis fungsi bash yang memiliki fungsi dasar yang sama dengan fungsi cp
(copy). Hanya perlu menyalin satu file ke yang lain, jadi tidak ada banyak file yang disalin ke direktori baru.
Karena saya baru menggunakan bahasa bash, saya tidak dapat mengerti mengapa program saya tidak berfungsi. Fungsi asli meminta untuk menimpa file jika sudah ada, jadi saya mencoba mengimplementasikannya. Itu gagal.
Tampaknya file gagal di beberapa baris, tetapi yang paling penting pada kondisi di mana ia memeriksa apakah file yang akan disalin sudah ada ( [-e "$2"]
). Meski begitu, masih menunjukkan pesan yang seharusnya dipicu jika kondisi itu terpenuhi (Nama file ...).
Adakah yang bisa membantu saya memperbaiki file ini, mungkin memberikan beberapa wawasan yang berguna dalam pemahaman dasar bahasa saya? Kode tersebut adalah sebagai berikut.
#!/bin/sh
echo "file variable: $2"
if [-e file]&> /dev/null
then
echo "The file name already exists, want to overwrite? (yes/no)"
read | tr "[A-Z]" "[a-z]"
if [$REPLY -eq "yes"] ; then
rm "$2"
echo $2 > "$2"
exit 0
else
exit 1
fi
else
cat $1 | $2
exit 0
fi
[ ... ] &> /dev/null
. Tes yang didukung oleh[ ... ]
selalu diam, itu hanya dalam kasus kesalahan sintaks yang dihasilkan output. Membungkam tes semacam itu hanyalah menggali kubur Anda sendiri.cat $1 | $2
"menyalurkan" output dari perintah pertama ke perintah di variabel kedua Anda. Tapi itu adalah nama file, bukan nama perintah untuk dieksekusi.[
perintah diif
.|
dan pengalihan ke file dengan>
. Ini adalah masalah sintaksis dasar yang seharusnya sudah dibahas di kelas Anda.Jawaban:
The
cp
utilitas akan dengan senang hati menimpa file target jika file yang sudah ada, tanpa disuruh pengguna.Suatu fungsi yang mengimplementasikan
cp
kemampuan dasar , tanpa menggunakancp
adalahJika Anda ingin meminta pengguna sebelum menimpa target (perhatikan bahwa mungkin tidak diinginkan untuk melakukan ini jika fungsinya dipanggil oleh shell non-interaktif):
Pesan diagnostik harus pergi ke aliran kesalahan standar. Inilah yang saya lakukan
printf ... >&2
.Perhatikan bahwa kita tidak benar-benar perlu ke
rm
file target karena pengalihan akan memotongnya. Jika kita memang menginginkannyarm
terlebih dahulu, maka Anda harus memeriksa apakah itu direktori, dan jika ya, letakkan file target di dalam direktori itu, seperti yangcp
akan dilakukan. Ini melakukan itu, tetapi masih tanpa eksplisitrm
:Anda juga mungkin ingin memastikan bahwa sumber benar-benar ada, yang merupakan sesuatu yang
cp
tidak lakukan (cat
melakukannya juga, sehingga dapat dibiarkan keluar sepenuhnya, tentu saja, tapi hal itu akan membuat file target kosong):Fungsi ini tidak menggunakan "bashism" dan harus bekerja di semua
sh
shell.Dengan sedikit penyesuaian lebih lanjut untuk mendukung banyak file sumber dan
-i
bendera yang mengaktifkan prompt interaktif saat menimpa file yang ada:Kode Anda memiliki spasi buruk
if [ ... ]
(butuh ruang sebelum dan sesudah[
, dan sebelum]
). Anda juga tidak boleh mencoba mengarahkan ulang tes/dev/null
karena tes itu sendiri tidak memiliki output. Tes pertama selanjutnya harus menggunakan parameter posisi$2
, bukan stringfile
.Menggunakan
case ... esac
seperti yang saya lakukan, Anda menghindari huruf kecil / huruf besar respon dari pengguna yang menggunakantr
. Dalambash
, jika Anda tetap ingin melakukan ini, cara yang lebih murah untuk melakukannya adalah dengan menggunakanREPLY="${REPLY^^}"
(untuk huruf besar) atauREPLY="${REPLY,,}"
(untuk huruf kecil).Jika pengguna mengatakan "ya", dengan kode Anda, fungsinya menempatkan nama file file target ke file target. Ini bukan menyalin file sumber. Seharusnya jatuh ke sedikit menyalin fungsi sebenarnya.
Bit penyalinan adalah sesuatu yang telah Anda terapkan menggunakan pipa. Pipeline digunakan untuk meneruskan data dari output dari satu perintah ke input dari perintah lain. Ini bukan sesuatu yang perlu kita lakukan di sini. Cukup memohon
cat
pada file sumber dan mengarahkan hasilnya ke file target.Hal yang sama salah dengan Anda menelepon
tr
sebelumnya.read
akan mengatur nilai variabel, tetapi tidak menghasilkan output, jadi pemipaanread
ke apa pun tidak masuk akal.Tidak diperlukan keluar secara eksplisit kecuali jika pengguna mengatakan "tidak" (atau fungsinya menemukan beberapa kondisi kesalahan seperti dalam bit kode saya, tetapi karena ini adalah fungsi yang saya gunakan
return
daripadaexit
).Juga, Anda mengatakan "berfungsi", tetapi implementasi Anda adalah skrip.
Lihatlah https://www.shellcheck.net/ , ini adalah alat yang baik untuk mengidentifikasi bit skrip shell yang bermasalah.
Menggunakan
cat
hanyalah salah satu cara untuk menyalin konten file. Cara lain termasukdd if="$1" of="$2" 2>/dev/null
sed "" "$1" >"2"
atauawk '1' "$1" >"$2"
atau lainnyatr '.' '.' <"$1" >"$2"
.Agak sulitnya adalah membuat fungsi menyalin metadata (kepemilikan dan izin) dari sumber ke target.
Satu hal yang perlu diperhatikan adalah bahwa fungsi yang saya tulis akan berperilaku sangat berbeda dari
cp
jika targetnya adalah/dev/tty
misalnya (file non-reguler).sumber
cat "$1" >"$2"
akan bekerja dalam 2 kali: shell pertama kali melihat> "$2"
, yang berarti: create-or-clobber (= kosong) file "$ 2", dan mengarahkan stdout perintah ke file itu. Kemudian meluncurkan perintahcat "$1"
:, dan mengarahkan kembali stdout ke file"$2"
(sudah dikosongkan atau dibuat kosong).-ef
perbandingan file danlocal -a
.-ef
menerima pemberitahuan jika kedua file tersebut sama (menangani tautan juga) danlocal -a
membuat variabel array lokal.