Saya memiliki kode ini yang berfungsi:
# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>/dev/null
else
# Get silly error messages when running from terminal
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName"
fi
Jika saya mencoba mempersingkatnya seperti ini:
# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" "$HideErrors"
Saya mendapat pesan kesalahan:
[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)
Mengapa argumen hard-coded berfungsi tetapi bukan argumen sebagai variabel?
Edit 2:
Saat ini saya menemukan kesuksesan dengan saran alternatif jawaban kedua:
# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null
google-chrome --headless --disable-gpu --dump-dom \
"$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"
Edit 1:
Berdasarkan jawaban pertama, saya harus menunjukkan header program yang sudah berisi:
[[ $fCron != true ]] &&
exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)
command-line
bash
redirect
WinEunuuchs2Unix
sumber
sumber
[[ $fCron == true ]] && exec 2>/dev/null
sebagai gantinyaJawaban:
Alasan Anda tidak dapat menyebabkan pengalihan terjadi dengan memperluas
"$HideErrors"
adalah bahwa simbol seperti>
tidak diperlakukan secara khusus setelah diproduksi oleh ekspansi parameter . Ini sebenarnya sangat bagus, karena simbol seperti itu muncul dalam teks yang mungkin ingin Anda kembangkan dan gunakan secara harfiah.Ini berlaku apakah Anda mengutip atau tidak
$HideErrors
. Hasil ekspansi parameter tunduk pada pemisahan kata dan globbing ketika ekspansi tersebut tidak dikutip, tetapi hanya itu saja.Adapun apa yang harus dilakukan tentang hal itu, ada banyak cara untuk mencapai pengalihan bersyarat. Untuk perintah yang sangat sederhana, mungkin masuk akal menulis seluruh perintah dua kali, sekali di setiap cabang
case
atauif
-else
konstruksi. Namun, ini segera menjadi beban, dan perintah yang Anda tunjukkan tentu saja merupakan kasus yang tidak ideal.Dari pendekatan yang memungkinkan Anda menghindari pengulangan sendiri , ada dua yang saya sarankan, karena mereka cukup bersih dan mudah diperbaiki. Anda ingin menggunakan hanya satu di antaranya, tidak sekaligus untuk perintah dan pengalihan yang sama.
Simpan perintah alih-alih pengalihan. Alih-alih mencoba menyimpan pengalihan dalam variabel dan menerapkan perluasan parameter, simpan perintah dalam fungsi shell . Kemudian tulis a
case
atauif
-else
, di mana fungsi dipanggil dengan pengalihan di satu cabang dan tanpa itu di yang lain.Jika Anda mengonseptualisasikan perintah sebagai kode yang ingin Anda tulis sekali tetapi dijalankan dalam berbagai keadaan, maka fungsi adalah solusi alami. Inilah yang biasanya saya lakukan. Ini memiliki manfaat tidak memerlukan subkulit atau penyimpanan manual dan pengaturan ulang negara.
Dengan kode Anda:
Anda dapat menerapkan jarak apa pun yang Anda suka, atau
if
-else
sebagai gantinya jika Anda mau. Perhatikan bahwalaunch
secara otomatis menggunakan pemanggilRobWebAddress
danDownloadName
variabel, bahkan jika mereka adalah variabel lokal, karena Bash secara dinamis dicakup , tidak seperti kebanyakan bahasa pemrograman yang dibatasi secara leksikal.Jalankan perintah dalam subkulit dan gunakan pengalihan secara kondisional
exec
. Inilah yang steeldriver berkomentar tentang , tetapi di dalam(
)
untuk menjaga efek lokal . Ketika paraexec
builtin dijalankan tanpa argumen, itu tidak menggantikan shell saat ini dengan proses baru, tapi bukannya berlaku setiap dari pengalihan kepada shell saat ini.(Mungkin juga untuk melacak kesalahan standar dan mengembalikannya, tanpa menggunakan subshell dan dengan demikian tanpa mengorbankan kemampuan untuk memodifikasi lingkungan shell saat ini. Namun, saya akan menyerahkan detailnya ke jawaban lain.)
Dengan kode Anda:
Setelah penutupan
)
, kesalahan standar berlaku dikembalikan ke apa pun sebelumnya, karena itu hanya benar-benar diarahkan di subkulit, dan bukan di shell induk. Ini juga berfungsi baik dengan variabel shell yang ada, karena subshell mendapatkan salinannya. Meskipun saya lebih suka menggunakan fungsi shell, saya akui metode ini mungkin memerlukan lebih sedikit kode.Kedua metode berfungsi terlepas dari apa standar kesalahan file atau perangkat dimulai, termasuk dalam kasus pengalihan diterapkan ke fungsi shell yang memanggil kode yang berisi perilaku kondisional, serta kasus (disebutkan dalam edit Anda) di mana kesalahan standar untuk seluruh skrip telah dialihkan oleh yang sebelumnya atau . Bahwa jalur diproduksi oleh proses substitusi tidak ada masalah.
exec 2>&fd
exec 2> path
sumber
exec
tidak tahu apakah dia merencanakan jawaban untuk itu ...exec
. Tapi, seperti yang saya sebutkan di atas, saya tidak membahas aplikasi yang lebih canggih di mana deskriptor file lama disimpan dan dipulihkan tanpa subkulit. Saya juga tidak membahas aplikasi yang kurang canggih, seperti hanya menjaga pengalihan jika ini adalah akhir dari skrip. Jawaban lain, jika diposting, dapat mencakup keduanya, dan mungkin lebih.exec
yang seharusnya tidak mempengaruhi jawaban Anda sama sekali.RobWebAddress
jelas merupakan konteks global.DownloadName
didefinisikan lokal tetapi harus konteks global. Untuk beberapa alasan fungsi anak mewarisi definisi lokal dari orang tua (untuk kecerdasanDownloadName
itu terlihat denganDownloadAsHTML ()
fungsi yang disebut olehUpdateOne ()
fungsi yang mendefinisikannya sebagai lokal. Sudah hari yang sulit :(Karena item sintaks tidak ditafsirkan dari nilai variabel yang diperluas. Artinya, ekspansi variabel tidak sama dengan mengganti referensi variabel dengan teks variabel di baris perintah. (Hal-hal seperti
;
,|
,&&
dan kutipan dll juga tidak khusus dalam nilai-nilai variabel.)Yang bisa Anda lakukan adalah menggunakan alias, atau menggunakan variabel untuk menahan hanya target pengalihan.
Alias yang hanya pengganti teks, sehingga mereka dapat terus item sintaksis, seperti operator dan kata kunci. Dalam skrip, Anda harus melakukannya
shopt expand_aliases
, karena secara default skrip tersebut dinonaktifkan di shell yang tidak interaktif. Jadi, ini mencetak2
(hanya):(Dan Anda juga bisa
alias jos=if niin=then soj=fi
dan kemudian menulis semua pernyataan if Anda dalam bahasa Finlandia. Saya yakin siapa pun yang membaca naskah akan menyukai Anda.)Atau, tulis pengalihan selalu, tetapi kontrol hanya target dengan variabel. Anda memerlukan target no-op untuk kasus di mana Anda tidak ingin mengubah ke mana output berjalan,
tetapiSebenarnya, menambahkan/dev/stderr
harus bekerja dalam kasus itu.2> /dev/stderr
bukan merupakan larangan karena cara Linux memperlakukan fd dibuka dari/proc/<pid>/fd
independen dari aslinya. Ini memengaruhi posisi posisi tulis dan akan mengacaukan output jika masuk ke file biasa.Ini harus bekerja dalam mode tambahan, meskipun (atau jika stderr pergi ke pipa atau ke terminal):
Jadi ulangi:
2> /dev/stderr
bisa pecah.sumber
expand_aliases
itu menakutkan karena program Anda dapat disandera oleh~/.bashrc
saya pikir.expand_aliases
agak menakutkan. Tetapi~/.bashrc
seharusnya tidak menjadi masalah karena hanya dibaca oleh shell interaktif, dan.profile
dan teman-teman yang mungkin menyebutnya hanya dibaca oleh shell login. Kerang non-login non-aktif seperti skrip seharusnya tidak menjalankan semua itu. (Tapi kemudian ada$BASH_ENV
, dan ternyata.bashrc
dibaca jika stdin terhubung ke soket jaringan. Betapa berbelit-belit itu bisa ...)2>> "$dst"
trik itu, tapi saya baru sadar itu tidak berfungsi dalam kasus umum, jadi lebih baik hati-hati dengan itu.Judul pertanyaan: "Bagaimana cara lulus 2> / dev / null sebagai variabel?" Ini sebenarnya bisa dilakukan menggunakan
eval
Jadi kita dapat menulis ulang sebagai
Di mana akses variabel tidak langsung mencegah ekspansi terjadi terlalu cepat pada sisa baris perintah.
Kutipan ganda dalam variabel berfungsi dengan baik.
sumber
DownloadName
- dan teks literalRobWebAddress
selalu digunakan untuk URL. Anda menggunakan$"
"
kutipan . Saya pikir ini mungkin tidak disengaja dan Anda mungkin ingin$
di dalam"
"
, tetapi Anda melakukannya dengan cara itu di kedua tempat, jadi saya tidak yakin. Saya pikir hanya> "$DownloadName"
harus memperbaikinya. Tapi saya mengerti Anda mungkin tidak suka itu, karena tidak sengaja menggabungkan argumen dan non-argumen denganeval
adalah salah satu alasan itu sangat berbahaya dan sangat tidak disarankan untuk menggunakaneval
perilaku gabungan.eval
menyatukan sebelum mengevaluasi. Tapi saya pikir cara lain untuk menuliskannya adalah cara menuliseval 'google-chrome --headless --disable-gpu --dump-dom "$RobWebAddress" > "$DownloadName" '"$HideErrors"
yang membingungkan yang menyerupai tampilan kode OP. Dan secara umum, menggunakaneval
untuk tugas-tugas yang tidak membutuhkannya itu buruk . (Tidak satu pun dari alasan ini - atau bahkan menjelaskan - kesalahan dan permusuhan balasan lama saya.)