-1

In a rather large project, I run into the following problem: while calculating the correct command in a bash script, I don't manage to make the script respect the double quote necessary for single arguments with a blank.

$ ./testo "two three"
ls -l "two three_DD_FF"  # <- Why does it look for two files HERE??
ls: cannot access '"two': No such file or directory
ls: cannot access 'three_DD_FF"': No such file or directory

"two three" is the single argument.

With two_three my code works, as to be expected:

$ ./testo two_three
ls -l "two_three_DD_FF"
ls: cannot access '"two_three_DD_FF"': No such file or directory

And this is the basic generic code that I could come up with:

#!/usr/bin/bash
cmd="ls -l"
trio=""'"'"${1}_DD"
trio="${cmd} ${trio}_FF"'"'""
echo ${trio}
${trio}

(I didn't find a less strange method than the one above for the strangely looking strong quote, but that is not my main concern here.)

What I don't understand is the problem in execution: ls -l "two three_DD_FF" in the line above still leads to searching for two files, despite of the double quotes; while the same line on the command prompt does a job as intended (that is, searching for file "two three_DD_FF":

$ ls -l "two three_DD_FF"
-rw-rw-r-- 1 myhome me 0 Aug 27 13:09 'two three_DD_FF'

That is, the line echo ${trio} shows a correct command (when executed on the command line, at least; while the same command, when executed from within a script, fails. It fails to respect the double quotes for the file name to be searched.

My questions:

  1. Why does the same command fail from within a script?
  2. Of course, how do I rectify the script, so that the call actually results in the correct output?
13
  • 1
    Your ls could be some weird alias check like this type ls Commented Aug 27, 2024 at 11:51
  • 1
    Paste your script at shellcheck.net for validation/recommendation. Imo no amount of quote could fix your script Commented Aug 27, 2024 at 12:56
  • 2
    This question is similar to: Why does shell ignore quoting characters in arguments passed to it through variables?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Aug 27, 2024 at 13:00
  • 1
    The way you call the script what you write in the script matters. If you write unquoted ${trio} it is always going to split on spaces no matter the content. You have to write constructs in the script that prevent splitting, but using quotes that you write, not generate, for example ls -l "$trio". You can't store commands in a variable - use function to store commands. Required reading mywiki.wooledge.org/BashFAQ/050 . Commented Aug 27, 2024 at 14:12
  • 1
    Unfortunately there is no specific close reason to click on for "didn't follow the tag instructions", you need to manually type that, and the site just picks one of the set it has available to click on to show as the close reason if anyone clicked on one of them. Your question wasn't in reality closed for not being about programming or being too basic, it was because the code contains errors that shellcheck, which the bash tag you used tells you to use before posting a bash question, would have told you about (and so the many people reading your code wouldn't have to address). Commented Aug 28, 2024 at 12:23

2 Answers 2

3

My recommendation: work with arrays:

#!/usr/bin/env bash
cmd=(ls -l)
trio=( "${cmd[@]}" "${1}_DD_FF" )
"${trio[@]}"
Sign up to request clarification or add additional context in comments.

Comments

1

Replacing the echo in your script by a xxd <<< ${trio}, we can see:

00000000: 6c73 202d 6c20 2274 776f 2074 6872 6565  ls -l "two three
00000010: 5f44 445f 4646 220a                      _DD_FF".

Your variable trio therefore contains the string ls -l "two three_DD_FF".

When you run ${trio}, which could be written simpler as $trio, bash applies word splitting on the string, which gives the following words:

0: ls
1: -l
2: "two
3: three_DD_FF"

Hence ls is called with an option parameter (-l) and two additional arguments, "two and three_DD_FF".

This is reflected in the error message about not finding "two and three_DD_FF".

2 Comments

Nice clear answer. But why do you have backticks on the first two items in your 0-4 list? It should just be: 0: ls then 1: -l then 2: "two then 3: three_DD_FF".
@Raven: No idea why they got there. I removed them. Thanks for telling me.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.