Saya telah mempelajari tentang baris perintah dan belajar bahwa |
(pipa) dimaksudkan untuk mengarahkan output dari perintah ke input yang lain. Jadi mengapa perintah ls | file
itu tidak berhasil?
file
input adalah salah satu dari lebih banyak nama file, seperti file filename1 filename2
ls
output adalah daftar direktori dan file pada folder, jadi saya pikir ls | file
seharusnya menunjukkan tipe file dari setiap file pada folder.
Namun ketika saya menggunakannya, hasilnya adalah:
Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
[-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
file -C [-m magicfiles]
file [--help]
Karena ada beberapa kesalahan dengan penggunaan file
perintah
command-line
ls
pipe
file-command
IanC
sumber
sumber
ls
, ini menunjukkan bahwa Anda ingin semua file di direktori saat ini ditangani denganfile
perintah. ... Jadi mengapa tidak dilakukan:,file *
yang akan membalas dengan baris untuk setiap file, folder.file *
adalah cara paling cerdas, saya hanya ingin tahu mengapa menggunakanls
output tidak berfungsi. Keraguan dihapus :)ls
umumnya merupakan ide yang buruk.Jawaban:
Masalah mendasar adalah bahwa
file
mengharapkan nama file sebagai argumen baris perintah, bukan pada stdin. Ketika Anda menulisls | file
outputls
sedang dikirimkan sebagai inputfile
. Bukan sebagai argumen, sebagai input.Apa bedanya?
Argumen baris perintah adalah ketika Anda menulis flag dan nama file setelah perintah, seperti pada
cmd arg1 arg2 arg3
. Dalam skrip shell argumen ini tersedia sebagai variabel$1
,$2
,$3
, dll di C Anda akan mengaksesnya melaluichar **argv
danint argc
argumen untukmain()
.Input standar, stdin, adalah aliran data. Beberapa program menyukai
cat
atauwc
membaca dari stdin ketika mereka tidak diberi argumen baris perintah. Dalam skrip shell yang dapat Anda gunakanread
untuk mendapatkan satu baris input. Di C Anda dapat menggunakanscanf()
ataugetchar()
, di antara berbagai opsi.file
biasanya tidak membaca dari stdin. Itu mengharapkan setidaknya satu nama file dilewatkan sebagai argumen. Itu sebabnya ia mencetak penggunaan saat Anda menulisls | file
, karena Anda tidak memberikan argumen.Anda dapat menggunakan
xargs
untuk mengubah stdin menjadi argumen, seperti padals | xargs file
. Meski begitu, seperti yang disebutkan terdon , penguraianls
adalah ide yang buruk. Cara paling langsung untuk melakukan ini adalah:sumber
file
untuk mendapatkan nama file dari inputnya, menggunakanls | file -f -
. Masih ide yang buruk.ls
keluaran pipa kefile
stdin. Cobalah.file $(ls)
, yang juga berfungsi, dengan cara lain.Karena, seperti yang Anda katakan, input
file
harus berupa nama file . Namun, output darils
hanya teks. Itu kebetulan daftar nama file tidak mengubah fakta bahwa itu hanya teks dan bukan lokasi file pada hard drive.Ketika Anda melihat output dicetak di layar, apa yang Anda lihat adalah teks. Apakah teks itu puisi atau daftar nama file tidak ada bedanya dengan komputer. Yang ia tahu hanyalah teks. Inilah sebabnya mengapa Anda dapat meneruskan output dari
ls
ke program yang menggunakan teks sebagai input (walaupun Anda benar-benar tidak seharusnya ):Jadi, untuk menggunakan output dari perintah yang mencantumkan nama file sebagai teks (seperti
ls
ataufind
) sebagai input untuk perintah yang menggunakan nama file, Anda perlu menggunakan beberapa trik. Alat khas untuk ini adalahxargs
:Seperti yang saya katakan sebelumnya, Anda benar-benar tidak ingin mem-parsing output dari
ls
. Sesuatu sepertifind
lebih baik (yangprint0
mencetak sebuah\0
bukannya newilne setelah setiap nama file dan-0
darixargs
memungkinkan itu berurusan dengan masukan tersebut; ini adalah trik untuk membuat perintah pekerjaan Anda dengan nama file yang berisi baris):Yang juga memiliki cara sendiri untuk melakukan ini, tanpa perlu
xargs
sama sekali:Akhirnya, Anda juga dapat menggunakan lingkaran shell. Namun, perhatikan bahwa dalam kebanyakan kasus,
xargs
akan jauh lebih cepat dan lebih efisien. Sebagai contoh:sumber
file
tidak muncul untuk benar-benar membaca stdin kecuali diberi eksplisit-
placeholder: membandingkanfile foo
,echo foo | file
danecho foo | file -
; sebenarnya itu mungkin alasan untuk pesan penggunaan dalam kasus OPs (yaitu itu tidak benar-benar karena output darils
"hanya teks", melainkan karena daftar argumenfile
kosong)echo foo | file -
tidak benar-benar berjalanfile
pada filefoo
tetapi pada aliran stdin.cat
itu kecuali stdin tanpa-
kecuali ketika diberikan argumen file juga saya kira?Itu tidak "mengarahkan" output, tetapi mengambil output dari suatu program dan menggunakannya sebagai input, sementara file tidak mengambil input tetapi nama file sebagai argumen , yang kemudian diuji. Pengalihan tidak lulus nama file ini sebagai argumen tidak perpipaan lakukan, nanti apa yang Anda lakukan.
Apa yang dapat Anda lakukan adalah membaca nama file dari file dengan
--files-from
opsi jika Anda memiliki file yang berisi daftar semua file yang ingin Anda uji, jika tidak cukup berikan path ke file Anda sebagai argumen.sumber
Jawaban yang diterima menjelaskan mengapa perintah pipa tidak bekerja secara langsung, dan dengan
file *
perintah itu, ia menawarkan solusi yang sederhana dan langsung.Saya ingin menyarankan alternatif lain yang mungkin berguna pada suatu waktu. Caranya adalah menggunakan
(`)
karakter backtick . Backtick dijelaskan dengan sangat rinci di sini . Singkatnya, dibutuhkan output dari perintah yang terlampir dalam backticks dan menggantikannya sebagai string ke dalam perintah yang tersisa.Jadi,
find `ls`
akan mengambil output darils
perintah, dan menggantinya sebagai argumen untukfind
perintah. Ini lebih panjang dan lebih rumit daripada solusi yang diterima, tetapi varian ini mungkin membantu dalam situasi lain.sumber
command
(tidak dapat menemukan kode backslash di ponsel saya) untuk memperluas output dari perintah di bash dan menggunakannya sebagai parameter untuk perintah lain. Sangat berguna, meskipun menggunakannya dalam kasus ini (dengan ls ) masih akan menghasilkan beberapa masalah karena karakter khusus pada beberapa nama file.Output dari
ls
melalui pipa adalah blok data yang solid dengan 0x0a memisahkan setiap baris - yaitu karakter linefeed - danfile
mendapatkan ini sebagai satu parameter, di mana ia mengharapkan beberapa karakter untuk bekerja pada satu per satu.Sebagai aturan umum, jangan pernah gunakan
ls
untuk menghasilkan sumber data untuk perintah lain - suatu hari nanti akan disalurkan .. kerm
dan kemudian Anda dalam masalah!Lebih baik menggunakan loop, seperti
for i in *; do file "$i" ; done
yang akan menghasilkan output yang Anda inginkan, dapat diprediksi. Kutipan ada dalam kasus nama file dengan spasi.sumber
file *
;-)ls
adalah ide yang sangat, sangat buruk . Bukan hanya karena Anda mungkin menularkannya ke sesuatu yang berbahaya sepertirm
, lebih penting karena itu terpecah pada nama file yang tidak standar.rm
mengambil nama file dari input standar? Saya pikir tidak. Juga, sebagai aturan umum,ls
telah menjadi salah satu contoh utama sumber data untuk penggunaan jaringan pipa Unix sejak awal Unix. Itu sebabnya ia default ke satu-nama file-per-line sederhana tanpa atribut atau perhiasan ketika outputnya adalah pipa, tidak seperti format default yang biasa ketika output adalah terminal.Jika Anda ingin menggunakan pipa untuk memberi makan
file
gunakan opsi-f
yang biasanya diikuti oleh nama file tetapi Anda juga dapat menggunakan tanda hubung tunggal-
untuk membaca dari stdin, jadiTrik dengan tanda hubung
-
berfungsi dengan banyak utils perintah-baris standar (meskipun--
kadang - kadang), jadi selalu patut dicoba.Alat
xarg
ini jauh lebih kuat dan dalam banyak kasus hanya diperlukan jika daftar argumen terlalu panjang (lihat posting ini untuk detailnya).sumber
--
? Saya belum pernah melihat itu.--
biasanya merupakan indikator "ujung bendera".Ini berfungsi menggunakan perintah seperti di bawah ini
Ini akan bekerja lebih baik untuk saya
sumber
Ini juga harus bekerja:
seperti juga dibahas di sini: https://unix.stackexchange.com/questions/5778/whats-the-difference-between-stuff-and-stuff
sumber
$()
metode adalah sama dengan metode backtick di askubuntu.com/a/795744/158442