GNU/Linux >> Belajar Linux >  >> Linux

Apakah Mungkin Menggunakan `find -exec Sh -c` Dengan Aman?

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 tanpa sh -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:

Terkait:Linux - linux yang setara dengan "Shake to Find Cursor" Mac?

<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 > {}'


Linux
  1. Bagaimana Cara Menggunakan Jenis File Di Vim?

  2. Apakah mungkin menggunakan / dalam nama file?

  3. Mengapa menggunakan shm_open?

  1. Cara menggunakan autofs untuk memasang share NFS

  2. Cara Menggunakan Perintah Tar di Linux

  3. Gunakan _roff Untuk Menggarisbawahi Kata?

  1. Mengapa saya menggunakan exa daripada ls di Linux

  2. Bagaimana cara menggunakan chmod untuk mengubah izin file?

  3. Kemungkinan untuk menggunakan .dll di Linux