Katakanlah jika saya menulis sebuah program dengan baris berikut:
int main(int argc, char** argv)
Sekarang ia tahu argumen baris perintah apa yang diteruskan dengan memeriksa konten argv
.
Bisakah program mendeteksi berapa banyak spasi di antara argumen? Seperti saat saya mengetik ini di bash:
ibug@linux:~ $ ./myprog aaa bbb
ibug@linux:~ $ ./myprog aaa bbb
Lingkungan adalah Linux modern (seperti Ubuntu 16.04), tetapi saya kira jawabannya harus berlaku untuk sistem yang mendukung POSIX.
Jawaban:
Tidak ada artinya berbicara tentang "ruang antar argumen"; itu konsep shell.
Tugas shell adalah mengambil seluruh baris input dan membentuknya menjadi array argumen untuk memulai perintah. Ini mungkin melibatkan parsing string yang dikutip, memperluas variabel, file wildcard dan ekspresi tilde, dan banyak lagi. Perintah dimulai dengan
exec
panggilan sistem standar , yang menerima vektor string.Ada cara lain untuk membuat vektor string. Banyak program bercabang dan mengeksekusi sub-proses mereka sendiri dengan permintaan perintah yang telah ditentukan - dalam hal ini, tidak pernah ada yang namanya "baris perintah". Demikian pula, shell grafis (desktop) mungkin memulai proses ketika pengguna menyeret ikon file dan menjatuhkannya pada widget perintah - sekali lagi, tidak ada baris teks untuk memiliki karakter "antara" argumen.
Sejauh menyangkut perintah yang dipanggil, apa yang terjadi di shell atau proses orangtua / prekursor lainnya bersifat pribadi dan tersembunyi - kita hanya melihat array string yang ditentukan oleh standar C yang
main()
dapat diterima.sumber
tar cf texts.tar *.txt
maka program tar mendapat dua argumen dan harus memperluas yang kedua (*.txt
) itu sendiri. Banyak orang tidak menyadari cara kerjanya hingga mereka mulai menulis skrip / program mereka sendiri yang menangani argumen.Secara umum, tidak. Penguraian baris perintah dilakukan oleh shell yang tidak membuat garis yang tidak diuraikan tersedia untuk program yang dipanggil. Bahkan, program Anda dapat dieksekusi dari program lain yang menciptakan argumen bukan dengan menguraikan string tetapi dengan membangun array argumen secara terprogram.
sumber
execve(2)
.Tidak, ini tidak mungkin, kecuali spasi merupakan bagian dari argumen.
Perintah mengakses argumen individu dari array (dalam satu bentuk atau lainnya tergantung pada bahasa pemrograman) dan baris perintah yang sebenarnya dapat disimpan ke file histori (jika diketik pada prompt interaktif di shell yang memiliki file histori), tetapi tidak pernah meneruskan perintah dalam bentuk apa pun.
Semua perintah pada Unix pada akhirnya dijalankan oleh salah satu
exec()
keluarga fungsi. Ini mengambil nama perintah dan daftar atau array argumen. Tak satu pun dari mereka mengambil baris perintah seperti yang diketik di prompt shell. Thesystem()
Fungsi tidak, tapi argumen string yang kemudian dieksekusi olehexecve()
, yang, sekali lagi, mengambil array argumen bukan string baris perintah.sumber
hello
dan secara harfiahworld
adalah spasi di antara dua argumen.hello
danworld
adalah harfiah memasok kedua dari tiga argumen.Secara umum, itu tidak mungkin, seperti beberapa jawaban lain yang dijelaskan.
Namun, shell Unix adalah program biasa (dan mereka menginterpretasikan baris perintah dan menggumpalkannya , yaitu memperluas perintah sebelum melakukan
fork
&execve
untuk itu). Lihat penjelasanbash
ini tentang operasi shell . Anda dapat menulis shell Anda sendiri (atau Anda dapat menambal beberapa shell perangkat lunak gratis yang ada , misalnya GNU bash ) dan menggunakannya sebagai shell Anda (atau bahkan shell login Anda, lihat passwd (5) & shells (5) ).Sebagai contoh, Anda mungkin memiliki program shell Anda sendiri meletakkan baris perintah penuh dalam beberapa variabel lingkungan (bayangkan
MY_COMMAND_LINE
misalnya) -atau menggunakan jenis lain komunikasi antar-proses untuk mengirimkan baris perintah dari shell ke proses anak-.Saya tidak mengerti mengapa Anda ingin melakukan itu, tetapi Anda mungkin membuat kode shell berperilaku sedemikian rupa (tapi saya sarankan tidak melakukannya).
BTW, suatu program dapat dimulai oleh beberapa program yang bukan shell (tetapi yang melakukan fork (2) kemudian mengeksekusi (2) , atau hanya
execve
memulai program dalam proses saat ini). Dalam hal ini tidak ada baris perintah sama sekali, dan program Anda dapat dimulai tanpa perintah ...Perhatikan bahwa Anda mungkin memiliki beberapa sistem Linux (khusus) tanpa shell yang terpasang. Ini aneh dan tidak biasa, tetapi mungkin. Anda kemudian harus menulis program init khusus memulai program lain sesuai kebutuhan - tanpa menggunakan shell apa pun tetapi dengan melakukan
fork
&execve
panggilan sistem.Baca juga Sistem Operasi: Tiga potong mudah dan jangan lupa bahwa
execve
praktis selalu merupakan panggilan sistem (di Linux, mereka terdaftar di syscalls (2) , lihat juga intro (2) ) yang menginisialisasi ulang ruang alamat virtual (dan beberapa lainnya) hal) dari proses melakukannya.sumber
argv[0]
untuk nama program dan elemen yang tersisa untuk argumen adalah spesifikasi POSIX dan tidak dapat diubah. Lingkungan runtime dapat menentukanargv[-1]
untuk baris perintah, saya berasumsi ...execve
dokumentasi dengan lebih cermat . Anda tidak dapat menggunakanargv[-1]
, itu adalah perilaku yang tidak ditentukan untuk menggunakannya.execvepluscmd
fungsi non-POSIX khusus dengan parameter tambahan (atau konvensi argv), syscall membangun vektor argumen untuk utama yang berisi pointer ke baris perintah sebelum pointer ke nama program, dan kemudian meneruskan alamat dari penunjuk ke nama program sepertiargv
ketika memanggil programmain
...sh
. Jadi bukan hal baru.Anda selalu dapat memberi tahu shell Anda untuk memberi tahu aplikasi apa yang menyebabkan kode shell dijalankan. Misalnya, dengan
zsh
, dengan meneruskan informasi itu dalam$SHELL_CODE
variabel lingkungan menggunakanpreexec()
hook (printenv
digunakan sebagai contoh, Anda akan menggunakannyagetenv("SHELL_CODE")
dalam program Anda):Semua itu akan dieksekusi
printenv
sebagai:Mengizinkan
printenv
untuk mengambil kode zsh yang mengarah ke eksekusiprintenv
dengan argumen tersebut. Apa yang ingin Anda lakukan dengan informasi itu tidak jelas bagi saya.Dengan
bash
, fitur yang paling dekat denganzsh
'spreexec()
akan menggunakan nya$BASH_COMMAND
dalamDEBUG
perangkap, tetapi catatan bahwabash
melakukan beberapa tingkat menulis ulang dalam (dan di refactors khususnya beberapa spasi digunakan sebagai pembatas) dan bahwa ini diterapkan pada setiap (baik, beberapa) perintah jalankan, bukan seluruh baris perintah seperti yang dimasukkan pada prompt (lihat jugafunctrace
opsi).Lihat bagaimana beberapa spasi yang merupakan pembatas dalam sintaksis bahasa shell telah diperas menjadi 1 dan bagaimana tidak, baris perintah penuh tidak selalu diteruskan ke perintah. Jadi mungkin tidak berguna dalam kasus Anda.
Perhatikan bahwa saya tidak akan menyarankan melakukan hal semacam ini, karena Anda berpotensi membocorkan informasi sensitif ke setiap perintah seperti pada:
akan membocorkan rahasia itu untuk keduanya
wc
danuntrustedcmd
.Tentu saja, Anda bisa melakukan hal semacam itu untuk bahasa lain selain shell. Misalnya, dalam C, Anda bisa menggunakan beberapa makro yang mengekspor kode C yang mengeksekusi perintah ke lingkungan:
Contoh:
Lihat bagaimana beberapa ruang dikondensasi oleh prosesor pra-C seperti dalam kasus bash. Dalam sebagian besar, jika tidak semua bahasa, jumlah ruang yang digunakan dalam pembatas tidak membuat perbedaan, jadi tidak mengherankan bahwa kompiler / penerjemah mengambil kebebasan di sini.
sumber
BASH_COMMAND
tidak mengandung argumen pemisahan spasi putih asli, jadi ini tidak dapat digunakan untuk permintaan literal OP. Apakah jawaban ini mencakup demonstrasi apa pun untuk kasus penggunaan tertentu?Saya hanya akan menambahkan apa yang hilang di jawaban lain.
Tidak
Lihat jawaban lain
Mungkin semacam
Tidak ada yang bisa dilakukan dalam program, tetapi ada sesuatu yang bisa dilakukan di shell ketika Anda menjalankan program.
Anda perlu menggunakan kutipan. Jadi, bukannya
Anda perlu melakukan salah satunya
Ini akan memberikan argumen tunggal ke program, dengan semua spasi. Ada perbedaan antara keduanya, yang kedua adalah literal, persis string yang muncul (kecuali yang
'
harus diketikkan sebagai\'
). Yang pertama akan menginterpretasikan beberapa karakter, tetapi dipecah menjadi beberapa argumen. Lihat kutipan shell untuk informasi lebih lanjut. Jadi tidak perlu menulis ulang shell, desainer shell sudah memikirkan itu. Namun karena sekarang menjadi satu argumen, Anda harus melakukan lebih banyak passing dalam program.pilihan 2
Lulus data melalui stdin. Ini adalah cara normal untuk mendapatkan sejumlah besar data ke dalam suatu perintah. misalnya
atau
./myprog
Tell me what you want to tell me:
aaaa bbb
ctrl-d
(Miring adalah hasil dari program)
sumber
./myprog␣"␣␣␣␣␣aaa␣␣␣␣␣␣bbb"
mengeksekusi (umumnya dalam proses anak) file yang disimpan dalam./myprog
dan meneruskannya dua argumen:./myprog
dan␣␣␣␣␣aaa␣␣␣␣␣␣bbb
(argv[0]
danargc[1]
,argc
menjadi 2) dan seperti dalam OP, ruang yang memisahkan kedua argumen tersebut tidak diteruskan dengan cara apa pun untukmyprog
.