0 Soalan: Gunakan arahan tersuai dalam rentetan [pendua]

soalan dicipta di Wed, May 8, 2019 12:00 AM

Saya menghadapi masalah yang menyampaikan hujah kepada arahan dalam skrip Bash.

poc.sh:

#!/bin/bash

ARGS='"hi there" test'
./swap ${ARGS}

swap:

#!/bin/sh
echo "${2}" "${1}"

Output semasa ialah:

there" "hi

Mengubah hanya poc.sh (seperti yang saya percaya swap melakukan apa yang saya mahu dengan betul), bagaimana saya mendapatkan poc.sh untuk lulus "hi there" dan menguji sebagai dua argumen, dengan "hi there" tidak ada petikan di sekeliling ia?

    
5
  1. Ini adalah topik BashFAQ # 50: mywiki.wooledge.org/BashFAQ/050
    2014-09-26 21: 22: 47Z
3 Jawapan                              3                         

Perkataan Pengenalan Sedikit

Sekiranya mungkin, jangan gunakan rentetan petikan shell sebagai format input.

  • Sukar untuk dihuraikan secara konsisten: Pelbagai shell mempunyai pelanjutan yang berbeza, dan pelaksanaan bukan shell yang berlainan melaksanakan subset yang berbeza (lihat delta di antara shlex dan xargs di bawah).
  • Sulit untuk menghasilkan program. ksh dan bash mempunyai printf '%q', yang akan menghasilkan rentetan sebutan shell dengan kandungan pembolehubah sewenang-wenangnya, tetapi tiada persamaan wujud dalam ini dalam standard POSIX sh.
  • Mudah untuk mengurai teruk . Ramai orang yang menggunakan format ini menggunakan eval, yang mempunyai kebimbangan keselamatan yang besar.

Saluran NUL-delimited adalah amalan yang jauh lebih baik, kerana mereka boleh mewakili mana-mana kemungkinan array atau senarai argumen tanpa sebarang kekaburan.


xargs, dengan bashisms

Jika anda memperoleh senarai hujah anda daripada sumber input manusia yang dihasilkan menggunakan petikan shell, anda mungkin mempertimbangkan untuk menggunakan xargs untuk mengurai. Pertimbangkan:

array=( )
while IFS= read -r -d ''; do
  array+=( "$REPLY" )
done < <(xargs printf '%s\0' <<<"$ARGS")

swap "${array[@]}"

... akan meletakkan kandungan parsed $ARGS ke array array. Jika anda ingin membaca dari fail sebaliknya, ganti <filename untuk <<<"$ARGS".


xargs, mematuhi POSIX

Jika anda cuba menulis kod yang mematuhi POSIX sh, ini menjadi lebih rumit. (Saya akan menganggap input fail di sini untuk mengurangkan kerumitan):

# This does not work with entries containing literal newlines; you need bash for that.
run_with_args() {
  while IFS= read -r entry; do
    set -- "$@" "$entry"
  done
  "$@"
}
xargs printf '%s\n' <argfile | run_with_args ./swap

Pendekatan ini lebih selamat daripada menjalankan xargs ./swap <argfile kerana ia akan membuang ralat jika terdapat hujah-hujah yang lebih panjang atau lebih daripada yang boleh ditampung, dan bukannya menjalankan hujah-hujah yang berlebihan sebagai perintah yang berasingan.


Python shlex - bukan xargs - dengan bashisms

Jika anda memerlukan parsing POSIX lebih tepat daripada melaksanakan xargs, pertimbangkan untuk menggunakan modul Python shlex:

shlex_split() {
  python -c '
import shlex, sys
for item in shlex.split(sys.stdin.read()):
    sys.stdout.write(item + "\0")
'
}
while IFS= read -r -d ''; do
  array+=( "$REPLY" )
done < <(shlex_split <<<"$ARGS")
    
17
2018-03-02 23: 54: 44Z
  1. Ini nampaknya tidak berfungsi dengan ARGS="\"a\\\"b\" c"? Ralat dilaporkan xargs: petikan berganda yang tidak dapat ditandingi; dengan sebut harga default adalah istimewa kepada xargs melainkan anda menggunakan opsyen -0
    2016-12-25 22: 03: 12Z
  2. Fair point - xargs memang tidak menghormati tingkah laku POSIX sh dalam kes itu. Mengemas kini dengan alternatif menggunakan fungsi Python 2's shlex.split().
    2016-12-26 18: 51: 12Z
  3. Perkara terbaik yang perlu dilakukan ialah meletakkan OP kembali di landasan yang betul: jika OP memerlukan perkara sedemikian, maka reka bentuk mereka jelas salah. Kecuali OP adalah menulis shell (atau cli), dalam hal ini pilihan bahasa adalah salah. Sama ada cara, OP melakukannya dengan salah.
    2016-12-26 19: 03: 36Z
  4. @ gniourf_gniourf, ... secara teori, saya setuju. Dalam praktiknya, orang-orang cenderung diberi syarat yang tidak masuk akal (atau memerlukan keserasian dengan sistem /amalan yang sudah lama) - terdapat satu langkah awal pengawasan warisan tan ipts untuk aplikasi Java yang terapung di sekitar yang bergantung pada eval senarai argumen yang diberikan dalam bentuk petikan shell), dan ada nilai dalam dapat membuat yang terbaik dari keadaan yang buruk ... walaupun pastinya, "jangan lakukan itu" sepatutnya sebahagian daripada nasihat yang diberikan.
    2016-12-26 19: 06: 31Z
  5. @ gniourf_gniourf, ... Saya telah diedit dalam pengenalan yang sesuai.
    2016-12-26 19: 09: 25Z

Sebut harga tertanam tidak melindungi ruang putih; mereka dirawat secara harfiah. Gunakan pelbagai di bash:

args=( "hi there" test)
./swap "${args[@]}"

Dalam shell POSIX, anda tersekat menggunakan eval (itulah sebabnya kebanyakan kerang menyokong array).

args='"hi there" test'
eval "./swap $args"

Seperti biasa, be sangat pasti anda tahu isi $args dan fahami bagaimana rentetan yang terhasil akan diurai sebelum menggunakan eval.

    
3
2014-09-26 19: 53: 42Z
  1. Saya cenderung untuk berhujah bahawa terdapat lebih banyak pilihan yang eval di sini. Malah di POSIX, seseorang boleh membaca ke "$@" dari xargs.
    2015-07-17 23: 07: 50Z

Ini mungkin bukan pendekatan yang paling teguh, tetapi ia mudah, dan kelihatannya berfungsi untuk kes anda:

## demonstration matching the question
$ ( ARGS='"hi there" test' ; ./swap ${ARGS} )
there" "hi

## simple solution, using 'xargs'
$ ( ARGS='"hi there" test' ; echo ${ARGS} |xargs ./swap )
test hi there
    
0
2017-03-10 23: 15: 47Z
  1. Commentary: Pemprosesan string Bash sangat mengelirukan. xargs membuang tekaan dengan melewatkan parameter secara langsung melalui exec , yang memintas normal, tidak berubah , pemprosesan rentetan yang Bash sebaliknya akan berfungsi sebagai sebahagian daripada pemproses baris perintah berasaskan string.
    2017-04-01 18: 13: 16Z
  2. Saya tidak pasti mengenai pernyataan saya mengenai exec. Tetapi saya berdiri dengan pernyataan saya bahawa "Pemprosesan tali Bash sangat mengelirukan" .
    2017-04-01 18: 23: 43Z
sumber diletakkan di sini