0

I have a bash script which is supposed to print the arguments in two lines. The first line should be the first argument and the second line should be the rest of the arguments

#!/bin/bash

FIRST_ARG="$1"
shift
REST_ARGS="$@"

echo $FIRST_ARG
echo $REST_ARGS

This works fine for normal arguments such as

root@us:~# /bin/bash parse.sh testName test1 test2 test3
testName
test1 test2 test3
root@us:~# 

However, what I want is to send a key value pair as the arguments such as

testName "X-Api-Key: 1be0ad48" "Name: someTest" "Interval: * * * * *"

I am expecting this to produce a result as follows

testName
"X-Api-Key: 1be0ad48" "Name: someTest" "Interval: * * * * *"

Including the quotes. However, I am getting the following as result

root@us:~# /bin/bash parse.sh testName "X-Api-Key: 1be0ad48" "Name: someTest" "Interval: * * * * *"
testName
X-Api-Key: 1be0ad48 Name: someTest Interval: parse.sh parse.sh parse.sh parse.sh parse.sh
root@us:~# 

Two things happening extra here that I don't want. 1) It removes the quotes ", 2) It replaces * with the file name.

I tried escaping those with " but it didn't work. Is there a way to solve this? Where am I doing wrong in this?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
zeroweb
  • 2,612
  • 4
  • 22
  • 34
  • The quotes are removed before the arguments are passed to the script, so what you want isn't really possible. But depending on *why* you want the quotes, it may be possible to accomplish your actual goal. Do the answers to ["Preserve Quotes in bash arguments"](https://stackoverflow.com/questions/10835933/preserve-quotes-in-bash-arguments) help? – Gordon Davisson Sep 15 '20 at 17:58
  • There is a very thorough explanation in the preamble to the accepted answer of https://unix.stackexchange.com/q/171346/4667 – glenn jackman Sep 15 '20 at 18:40
  • Whether you write `cmd a b` or `cmd "a" "b"`, cmd is called with the same arguments, and those arguments do not have quotes in them. They are just the strings `a` and `b`. – William Pursell Sep 15 '20 at 18:56

3 Answers3

1

The only sure way to stash command line arguments is in an array:

#!/bin/bash

first_arg="$1"
shift
rest_args=("$@")
# ........^....^

# show how bash has stored these variables
declare -p first_arg
declare -p rest_args

echo "first = $first_arg"
for arg in "${rest_args[@]}"; do
    echo "arg = $arg"
done

Get out of the habit of using ALLCAPS variable names, leave those as reserved by the shell. One day you'll write PATH=something and then wonder why your script is broken.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

the * are expanded because you are doing a echo without quoting $REST_ARGS. try adding quotes like this:

#!/bin/bash

FIRST_ARG="$1"
shift
REST_ARGS="$@"

echo "$FIRST_ARG"
echo "$REST_ARGS"

a solution to keep the double quotes would be to quote the strings using single quote ' like this:

$ bash parse.sh testName '"X-Api-Key: 1be0ad48"' '"Name: someTest"' '"Interval: * * * * *"'
testName
"X-Api-Key: 1be0ad48" "Name: someTest" "Interval: * * * * *"
$
MarcoLucidi
  • 2,007
  • 1
  • 5
  • 8
  • 1
    That still stores the rest of the args as a single string in the REST_ARGS variable, although you have protected the word splitting and pathname expansion. Generally, storing literal quotes in the arguments is a bad idea: the commands you pass the arguments to will have to deal with the literal quotes, or throw errors – glenn jackman Sep 15 '20 at 18:45
  • @glennjackman `That still stores the rest of the args as a single string in the REST_ARGS variable` is it a problem in this particular case? I agree that storing quotes in arguments is a bad idea, but I understood from the question that OP wants to keep them. – MarcoLucidi Sep 15 '20 at 19:17
0

Does what you ask for:

#!/usr/bin/env sh

echo "$1"
shift
printf '"%s" ' "$@"
# or alternatively:
# env printf '%q ' "$@"
echo
Léa Gris
  • 17,497
  • 4
  • 32
  • 41