Memproses semua argumen kecuali yang pertama (dalam skrip bash)

444

Saya memiliki skrip sederhana di mana argumen pertama dicadangkan untuk nama file, dan semua argumen opsional lainnya harus diteruskan ke bagian lain dari skrip.

Menggunakan Google, saya menemukan wiki ini , tetapi memberikan contoh literal:

echo "${@: -1}"

Saya tidak bisa mendapatkan pekerjaan lain, seperti:

echo "${@:2}"

atau

echo "${@:2,1}"

Saya mendapatkan "substitusi buruk" dari terminal.

Apa masalahnya, dan bagaimana saya bisa memproses semua kecuali argumen pertama diteruskan ke skrip bash?

theta
sumber
21
Untuk memanggil siapa pun yang bingung, shebang yang salah disediakan sehingga "{@:2}"tidak berfungsi, itulah sebabnya jawaban yang benar cocok dengan di atas.
Guvante
3
Anda hanya menggunakan shell default, yang dash pada Ubuntu dan banyak Linux lainnya. Dalam tanda hubung "$ {@: -1}" diartikan sebagai: {parameter: -word} - Gunakan Nilai Default, dan gunakan kata jika parameter tidak didefinisikan atau nol. Jadi pada tanda hubung "$ {@: -1}" hasilnya persis sama dengan "$ @". Untuk menggunakan bash cukup gunakan baris pertama berikut dalam file skrip: #! / Bin / bash
luart

Jawaban:

660

Gunakan ini:

echo "${@:2}"

Sintaks berikut:

echo "${*:2}"

akan bekerja dengan baik, tetapi tidak direkomendasikan, karena seperti yang telah dijelaskan @Gordon , bahwa menggunakan *, ia menjalankan semua argumen bersama sebagai argumen tunggal dengan spasi, sambil @mempertahankan jeda di antara mereka (bahkan jika beberapa argumen sendiri berisi spasi ). Itu tidak membuat perbedaan dengan echo, tetapi itu penting untuk banyak perintah lainnya.

Oliver Charlesworth
sumber
7
Saya baru menyadari bahwa shebang saya buruk: #!/usr/bin/env shItu sebabnya saya punya masalah. Anda contoh berfungsi dengan baik, sama seperti yang disediakan di atas, setelah saya menghapus shebang itu
theta
110
Gunakan "${@:2}"sebaliknya - menggunakan *menjalankan semua argumen bersama sebagai argumen tunggal dengan spasi, sambil @mempertahankan jeda di antara keduanya (bahkan jika beberapa argumen sendiri berisi spasi). Perbedaannya tidak terlihat dengan echo, tetapi itu penting untuk banyak hal lainnya.
Gordon Davisson
2
@GordonDavisson Intinya di sini adalah untuk menjalankan argumen bersama. Jika kami melewati nama file, Anda akan benar. echocukup memaafkan untuk menyatukan mereka untuk Anda; perintah lain mungkin tidak begitu baik. Jangan hanya menggunakan satu atau yang lain: pelajari perbedaan antara *dan @, dan kapan menggunakannya. Anda harus menggunakannya tentang sama. Contoh yang baik ketika ini akan menjadi masalah: jika $3berisi pemisah baris ( \n), itu akan diganti dengan spasi, asalkan Anda memiliki $IFSvariabel default .
Zenexer
1
@ Zenexer: Seperti yang saya pahami, pertanyaannya adalah bagaimana meneruskan semua kecuali argumen pertama ke "ke bagian lain dari skrip", dengan echohanya digunakan sebagai contoh - dalam hal ini mereka tidak boleh dijalankan bersama. Dalam pengalaman saya, situasi di mana Anda ingin mereka berjalan bersama jarang terjadi (lihat pertanyaan ini sebagai contoh ), dan "$@"hampir selalu seperti yang Anda inginkan. Selain itu, masalah yang Anda sebutkan dengan jeda baris hanya terjadi jika $@(atau $*) tidak ada tanda kutip ganda.
Gordon Davisson
@ GordonDavisson Hmm ... Anda benar, sekarang saya memikirkannya; istirahat baris seharusnya tidak menjadi masalah. Saya pasti memikirkan sesuatu yang lain. Namun, saya masih harus tidak setuju tentang menjalankannya bersama; Saya perlu $*cukup sering menggunakan skrip saya.
Zenexer
180

Jika Anda menginginkan solusi yang juga berfungsi di /bin/shcoba

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n]menggeser parameter posisi n kali. A shiftmengatur nilai $1ke nilai $2, nilai $2ke nilai$3 , dan seterusnya, mengurangi nilai $#satu.

Ben Jackson
sumber
25
+1: Anda mungkin harus menyimpan $ 1 ke dalam variabel sebelum memindahkannya.
glenn jackman
3
Anehnya foo=shifttidak melakukan apa yang saya harapkan.
Keith Smiley
Saya tahu ini sudah tua, tetapi cobafoo=$(shift)
raumaan kidwai
12
@raumaankidwai Itu tidak berfungsi karena 2 alasan: 1) shift(dalam shell) tidak memiliki output. Itu hanya membuang $1dan menggeser semuanya ke bawah. 2) $(...)memulai subkulit, yang memiliki argumen lokalnya sendiri. Ini menggeser argumen dalam subkulit, yang tidak mempengaruhi orangtua
Ben Jackson
Terima kasih :) Apakah ada cara untuk melakukan apa yang somecommand "$1" "${@:2}"dilakukan dengan metode ini (yaitu shift "inline")?
Anonim
0

Datang ini mencari sesuatu yang lain. Sementara pos terlihat cukup tua, solusi termudah dalam bash diilustrasikan di bawah ini (setidaknya bash 4) menggunakan di set -- "${@:#}"mana # adalah angka awal dari elemen array yang ingin kita pertahankan:

    #!/bin/bash

    someVar="${1}"
    someOtherVar="${2}"
    set -- "${@:3}"
    input=${@}

    [[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"

    echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"

Pada dasarnya, set -- "${@:3}"hanya muncul dari dua elemen pertama dalam array seperti pergeseran perl dan mempertahankan semua elemen yang tersisa termasuk yang ketiga. Saya curiga ada cara untuk menghilangkan elemen terakhir juga.

Pavman
sumber