简体   繁体   中英

Bash Script - Nested $(..) Commands - Not working correctly

I was trying to do these few operations/commands on a single line and assign it to a variable. I have it working about 90% of the way except for one part of it.

I was unaware you could do this, but I read that you can nest $(..) inside other $(..).... So I was trying to do that to get this working, but can't seem to get it the rest of the way.

So basically, what I want to do is:
1. Take the output of a file and assign it to a variable
2. Then pre-pend some text to the start of that output
3. Then append some text to the end of the output
4. And finally remove newlines and replace them with "\\n" character...

I can do this just fine in multiple steps but I would like to try and get this working this way.

So far I have tried the following:

My 1st attempt, before reading about nested $(..):

MY_VAR=$(echo -n "<pre style=\"display:inline;\">"; cat input.txt | sed ':a;N;$!ba;s/\n/\\n/g'; echo -n "</pre>")

This one worked 99% of the way except there was a newline being added between the cat command's output and the last echo command. I'm guessing this is from the cat command since sed removed all newlines except for that one, maybe...?

Other tries:

MY_VAR=$( $(echo -n "<pre style=\"display:inline;\">"; cat input.txt; echo -n "</pre>") | sed ':a;N;$!ba;s/\n/\\n/g')

MY_VAR="$( echo $(echo -n "<pre style=\"display:inline;\">"; cat input.txt; echo "</pre>") | sed ':a;N;$!ba;s/\n/\\n/g' )"

MY_VAR="$( echo "$(echo -n "<pre style=\"display:inline;\">"; cat input.txt; echo "</pre>")" | sed ':a;N;$!ba;s/\n/\\n/g' )"

*Most these others were tried with and without the extra double-quotes surrounding the different $(..) parts...

I had a few other attempts, but they didn't have any luck either... On a few of the other attempts above, it seemed to work except sed was NOT inserting the replacement part of it. The output was correct for the most part, except instead of seeing "\\n" between lines it just showed each of the lines smashed together into one line without anything to separate them...

I'm thinking there is something small I am missing here if anyone has any idea..?

*PS Does Bash have a name for the $(..) structure? It's hard trying to Google for that since it doesn't really search symbols...

You have no need to nest command substitutions here.

your_var='<pre style="display:inline;">'"$(<input.txt)"'</pre>'
your_var=${your_var//$'\n'/'\n'}

  • "$(<input.txt)" expands to the contents of input.txt , but without any trailing newline. (Command substitution always strips trailing newlines; printf '%s' "$(cat ...)" has the same effect, albeit less efficiently as it requires a subshell, whereas cat ... alone does not).
  • ${foo//bar/baz} expands to the contents of the shell variable named foo , with all instances of bar replaced with baz .
  • $'\\n' is bash syntax for a literal newline.
  • '\\n' is bash syntax for a two-character string, beginning with a backslash.
  • Thus, tying all this together, it first generates a single string with the prefix, the contents of the file, and the suffix; then replaces literal newlines inside that combined string with '\\n' two-character sequences.

Granted, this is multiple lines as implemented above -- but it's also much faster and more efficient than anything involving a command substitution.


However, if you really want a single, nested command substitution, you can do that:

your_var=$(printf '%s' '<pre style="display:inline;">' \
                       "$(sed '$ ! s/$/\\n/g' <input.txt | tr -d '\n')" \
                       '</pre>')
  • The printf %s combines its arguments without any delimiter between them
  • The sed operation adds a literal \\n to the end of each line except the last
  • The tr -d '\\n' operation removes literal newlines from the file

However, even this approach could be done more efficiently without the nesting:

printf -v your_var '%s' '<pre style="display:inline;">' \
                        "$(sed '$ ! s/$/\\n/g' <input.txt | tr -d '\n')" \
                        '</pre>')

...which has the printf assign its results directly to your_var , without any outer command substitution required (and thus saving the expense of the outer subshell).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM