Saya mencoba menggunakan find
untuk echo 0
ke dalam beberapa file, tetapi tampaknya ini hanya berfungsi dengan sh -c
:
find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' ;
Tetapi menggunakan sh -c
dengan find -exec
membuat saya merasa sangat tidak nyaman karena saya curiga mengutip masalah. Saya sedikit mengutak-atiknya dan ternyata kecurigaan saya beralasan:
-
Pengaturan pengujian saya:
[email protected] ~ % cd findtest [email protected] ~/findtest % echo one > file with spaces [email protected] ~/findtest % echo two > file with 'single quotes' [email protected] ~/findtest % echo three > file with "double quotes" [email protected] ~/findtest % ll insgesamt 12K -rw-rw-r-- 1 martin martin 6 Sep 17 12:01 file with "double quotes" -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with 'single quotes' -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with spaces
-
Menggunakan
find -exec
tanpash -c
tampaknya berfungsi tanpa masalah – tidak perlu mengutip di sini:[email protected] ~ % find findtest -type f -exec cat {} ; one two three
-
Tetapi ketika saya menggunakan
sh -c
{}
tampaknya memerlukan semacam kutipan:[email protected] ~ % LANG=C find findtest -type f -exec sh -c 'cat {}' ; cat: findtest/file: No such file or directory cat: with: No such file or directory cat: spaces: No such file or directory cat: findtest/file: No such file or directory cat: with: No such file or directory cat: single quotes: No such file or directory cat: findtest/file: No such file or directory cat: with: No such file or directory cat: double quotes: No such file or directory
-
Tanda kutip ganda berfungsi selama tidak ada nama file yang mengandung tanda kutip ganda:
[email protected] ~ % LANG=C find findtest -type f -exec sh -c 'cat "{}"' ; one two cat: findtest/file with double: No such file or directory cat: quotes: No such file or directory
-
Tanda kutip tunggal berfungsi selama tidak ada nama file yang berisi tanda kutip tunggal:
[email protected] ~ % LANG=C find findtest -type f -exec sh -c "cat '{}'" ; one cat: findtest/file with single: No such file or directory cat: quotes: No such file or directory three
Saya belum menemukan solusi yang berfungsi di semua kasus. Apakah ada sesuatu yang saya abaikan, atau menggunakan sh -c
di find -exec
secara inheren tidak aman?
Jawaban yang Diterima:
Jangan pernah menyematkan {}
dalam kode shell! Itu menciptakan kerentanan injeksi perintah. Perhatikan bahwa untuk cat "{}"
, ini bukan hanya tentang "
karakter, ,
`
, $
juga merupakan masalah (pertimbangkan misalnya file bernama ./$(reboot)/accept_ra
)¹.
Di sini, Anda ingin meneruskan nama file sebagai argumen terpisah ke sh
(tidak ada di kode argumen), dan sh
skrip sebaris (kode argumen) untuk merujuknya menggunakan parameter posisi:
find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} ;
Atau, untuk menghindari menjalankan satu sh
per berkas:
find . -name accept_ra -exec sh -c 'for file do
echo 0 > "$file"; done' sh {} +
Hal yang sama berlaku untuk xargs -I{}
atau zsh
zargs -I{}
. Jangan menulis:
<list.txt xargs -I{} sh -c 'cmd > {}'
Yang akan menjadi kerentanan injeksi perintah dengan cara yang sama seperti dengan find
di atas, tetapi:
<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh
Yang juga memiliki manfaat menghindari menjalankan satu sh
per file dan kesalahan saat list.txt
tidak berisi file apa pun.
Dengan zsh
zargs
, Anda mungkin ingin menggunakan fungsi daripada menjalankan sh -c
:
do-it() cmd > $1
zargs ./*.txt -- do-it
Perhatikan bahwa dalam semua contoh di atas sh
second kedua di atas masuk ke $0
skrip sebaris . Anda harus menggunakan sesuatu yang relevan di sana (seperti sh
atau find-sh
), bukan hal-hal seperti _
, -
, --
atau string kosong, sebagai nilai dalam $0
digunakan untuk pesan kesalahan shell:
$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} ;
inline-sh: ./accept_ra: Permission denied
GNU parallel
bekerja secara berbeda. Dengan itu, Anda tidak ingin menggunakan sh -c
sebagai parallel
sudah menjalankan shell dan mencoba mengganti {}
dengan argumen yang dikutip dalam sintaks yang tepat untuk shell.
<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'