Katakanlah, saya punya file yang foo.txt
menentukan N
argumen
arg1
arg2
...
argN
yang perlu saya sampaikan ke perintah my_command
Bagaimana cara menggunakan baris file sebagai argumen dari suatu perintah?
Katakanlah, saya punya file yang foo.txt
menentukan N
argumen
arg1
arg2
...
argN
yang perlu saya sampaikan ke perintah my_command
Bagaimana cara menggunakan baris file sebagai argumen dari suatu perintah?
Jawaban:
Jika shell Anda adalah bash (antara lain), pintasannya $(cat afile)
adalah $(< afile)
, jadi Anda akan menulis:
mycommand "$(< file.txt)"
Didokumentasikan di halaman bash man di bagian 'Pergantian Perintah'.
Alterately, minta perintah Anda dibaca dari stdin, jadi: mycommand < file.txt
<
operator. Ini berarti bahwa shell itu sendiri akan melakukan redirection daripada mengeksekusi cat
binary untuk properti redirection itu.
"$(…)"
, isi file.txt
akan diteruskan ke input standar mycommand
, bukan sebagai argumen. "$(…)"
berarti menjalankan perintah dan mengembalikan output sebagai string ; di sini "perintah" hanya membaca file tetapi bisa jadi lebih kompleks.
Seperti yang telah disebutkan, Anda dapat menggunakan backticks atau $(cat filename)
.
Apa yang tidak disebutkan, dan saya pikir penting untuk dicatat, adalah bahwa Anda harus ingat bahwa shell akan memecah konten file tersebut sesuai dengan spasi, memberikan setiap "kata" yang ditemukannya pada perintah Anda sebagai argumen. Dan sementara Anda mungkin bisa melampirkan argumen baris perintah dalam tanda kutip sehingga bisa berisi spasi, urutan melarikan diri, dll., Membaca dari file tidak akan melakukan hal yang sama. Misalnya, jika file Anda mengandung:
a "b c" d
argumen yang akan Anda dapatkan adalah:
a
"b
c"
d
Jika Anda ingin menarik setiap baris sebagai argumen, gunakan konstruksi while / read / do:
while read i ; do command_name $i ; done < filename
read -r
kecuali Anda ingin memperluas urutan backslash-escape - dan NUL adalah pembatas yang lebih aman untuk digunakan daripada baris baru, terutama jika argumen yang Anda sampaikan adalah hal-hal seperti nama file, yang dapat berisi baris baru literal. Juga, tanpa membersihkan IFS, Anda bisa memimpin dan mengikuti spasi kosong secara implisit dibersihkan i
.
command `< file`
akan meneruskan konten file ke perintah pada stdin, tetapi akan menghapus baris baru, yang berarti Anda tidak dapat mengulangi setiap baris secara terpisah. Untuk itu Anda bisa menulis skrip dengan loop 'untuk':
for line in `cat input_file`; do some_command "$line"; done
Atau (varian multi-baris):
for line in `cat input_file`
do
some_command "$line"
done
Atau (varian multi-baris dengan $()
alih - alih ``
):
for line in $(cat input_file)
do
some_command "$line"
done
< file
backticks berarti tidak benar-benar melakukan pengalihan command
sama sekali.
command `< file`
Tidak berfungsi baik di bash atau POSIX sh; zsh adalah masalah yang berbeda, tapi itu bukan masalah yang ditanyakan oleh pertanyaan ini).
Hello World
di satu baris. Anda akan melihatnya dijalankan pertama kali some_command Hello
, kemudian some_command World
, tidak some_command "Hello World"
atau some_command Hello World
.
Anda melakukannya dengan menggunakan backticks:
echo World > file.txt
echo Hello `cat file.txt`
echo "Hello * Starry * World" > file.txt
pada langkah pertama, Anda akan mendapatkan setidaknya empat argumen terpisah dilewatkan ke perintah kedua - dan kemungkinan lebih lanjut, karena *
s akan diperluas ke nama-nama file yang ada di direktori saat ini.
fork()
keluar dari subkulit dengan FIFO yang melekat pada stdout, kemudian memanggil /bin/cat
sebagai anak dari subkulit itu, kemudian membaca output melalui FIFO; dibandingkan dengan $(<file.txt)
, yang membaca konten file menjadi bash secara langsung tanpa subshell atau FIFO yang terlibat.
Jika Anda ingin melakukan ini dengan cara yang kuat yang bekerja untuk setiap argumen baris perintah yang mungkin (nilai dengan spasi, nilai dengan baris baru, nilai dengan karakter kutipan literal, nilai yang tidak dapat dicetak, nilai dengan karakter glob, dll), itu akan sedikit lebih menarik.
Untuk menulis ke file, diberikan array argumen:
printf '%s\0' "${arguments[@]}" >file
... ganti dengan "argument one"
,"argument two"
, dll yang sesuai.
Untuk membaca dari file itu dan menggunakan kontennya (dalam bash, ksh93, atau shell terbaru lainnya dengan array):
declare -a args=()
while IFS='' read -r -d '' item; do
args+=( "$item" )
done <file
run_your_command "${args[@]}"
Untuk membaca dari file itu dan menggunakan isinya (dalam shell tanpa array; perlu diketahui bahwa ini akan menimpa daftar argumen baris perintah lokal Anda, dan dengan demikian paling baik dilakukan di dalam suatu fungsi, sehingga Anda menimpa argumen fungsi dan tidak daftar global):
set --
while IFS='' read -r -d '' item; do
set -- "$@" "$item"
done <file
run_your_command "$@"
Perhatikan bahwa -d
(memungkinkan pembatas end-of-line yang berbeda untuk digunakan) adalah ekstensi non-POSIX, dan shell tanpa array juga mungkin tidak mendukungnya. Jika demikian, Anda mungkin perlu menggunakan bahasa non-shell untuk mengubah konten yang dibatasi NUL menjadi eval
bentuk -safe:
quoted_list() {
## Works with either Python 2.x or 3.x
python -c '
import sys, pipes, shlex
quote = pipes.quote if hasattr(pipes, "quote") else shlex.quote
print(" ".join([quote(s) for s in sys.stdin.read().split("\0")][:-1]))
'
}
eval "set -- $(quoted_list <file)"
run_your_command "$@"
Inilah cara saya meneruskan konten file sebagai argumen ke perintah:
./foo --bar "$(cat ./bar.txt)"
$(<bar.txt)
(saat menggunakan shell, seperti bash, dengan ekstensi yang sesuai). $(<foo)
adalah kasus khusus: tidak seperti substitusi perintah biasa, seperti yang digunakan $(cat ...)
, itu tidak memotong subkulit untuk beroperasi, dan dengan demikian menghindari banyak overhead.
Jika semua yang perlu Anda lakukan adalah mengubah file arguments.txt
dengan konten
arg1
arg2
argN
ke dalam my_command arg1 arg2 argN
maka Anda cukup menggunakan xargs
:
xargs -a arguments.txt my_command
Anda dapat memasukkan argumen statis tambahan dalam xargs
panggilan, seperti xargs -a arguments.txt my_command staticArg
yang akan dipanggilmy_command staticArg arg1 arg2 argN
Di bash shell saya yang berikut ini berfungsi seperti pesona:
cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'
di mana input_file berada
arg1
arg2
arg3
Sebagai bukti, ini memungkinkan Anda untuk mengeksekusi banyak perintah dengan setiap baris dari input_file, trik kecil yang bagus yang saya pelajari di sini .
$(somecommand)
, Anda akan mendapatkan perintah yang dieksekusi daripada diteruskan sebagai teks. Demikian juga, >/etc/passwd
akan diproses sebagai pengalihan dan ditimpa /etc/passwd
(jika dijalankan dengan izin yang sesuai), dll.
xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _
- dan juga lebih efisien, karena ia meneruskan sebanyak mungkin argumen ke setiap shell daripada memulai satu shell per baris dalam file input Anda.
cat
Setelah mengedit jawaban @Wesley Rice beberapa kali, saya memutuskan bahwa perubahan saya menjadi terlalu besar untuk terus mengubah jawabannya daripada menulis sendiri. Jadi, saya memutuskan untuk menulis sendiri!
Baca setiap baris file di dan operasikan baris demi baris seperti ini:
#!/bin/bash
input="/path/to/txt/file"
while IFS= read -r line
do
echo "$line"
done < "$input"
Ini datang langsung dari penulis Vivek Gite di sini: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ . Dia mendapat pujian!
Sintaks: Baca baris demi baris file pada shell Bash Unix & Linux:
1. Sintaksnya adalah sebagai berikut untuk bash, ksh, zsh, dan semua shell lain untuk membaca file baris demi baris
2.while read -r line; do COMMAND; done < input.file
3.-r
Opsi dilewatkan untuk membaca perintah mencegah backslash lolos dari ditafsirkan.
4. TambahkanIFS=
opsi sebelum membaca perintah untuk mencegah pemangkasan spasi awal / akhir -
5.while IFS= read -r line; do COMMAND_on $line; done < input.file
Dan sekarang untuk menjawab pertanyaan yang sekarang ditutup ini yang saya juga punya: Apakah mungkin untuk `git menambahkan` daftar file dari file?- inilah jawaban saya:
Perhatikan bahwa FILES_STAGED
ini adalah variabel yang berisi path absolut ke file yang berisi banyak baris di mana setiap baris adalah path relatif ke file yang ingin saya lakukan git add
. Cuplikan kode ini akan menjadi bagian dari file "eRCaGuy_dotfiles / useful_scripts / sync_git_repo_to_build_machine.sh" dalam proyek ini, untuk memudahkan sinkronisasi file dalam pengembangan dari satu PC (mis: komputer tempat saya berkode ) ke yang lain (mis: komputer tempat saya berkode )) komputer yang lebih kuat yang saya bangun): https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles .
while IFS= read -r line
do
echo " git add \"$line\""
git add "$line"
done < "$FILES_STAGED"
git add
padanya: Apakah mungkin untuk `git menambah` daftar file dari file?