Preserve quotes using $* redirected to file.
I'm writing a function for saving a command to a file from a script, but it won't preserve the single and double quotes inside of the command.
It does work from the shell if I do while surrounding it with 'single quotes' (simple example): > echo 'rsync --exclude="/etc"' >> ~/file.txt But if I do almost the same thing within a bash script it strips the quotes: > echo "$*" >> ~/file.txt I'm not talking about "quoting the beginning and end of entire command" I'm needing all the single/double quotes from within the command arguments because a lot of these commands going forward I want to save are long and complex with quoting. I've tried creating an array hoping would preserve it all, but same results. > commands=($*) > echo ${commands[*]} >> ~/file.txt Tried with $@ but breaks my command into multiple lines instead of single like if using $* This is the actual code I'm using from my script: > printf "%s\n" "$*" >> "${notefile}" and I've tried using ' %q' within printf, but it adds a bunch of \backslashes\ all over the line of code still missing the single/double quotes. I've tried '"$*"' (single quotes) since the single quotes work if I do the same thing from the shell itself, but it echo's the actual "$*" into the file and not the command. If I use single quotes around the array '${commands[*]' it puts the actual array ${commands[*]} in the file and not the command itself. |
Frankly, I never use "$*", I always use "$@".
I forget the reasoning, but you should run your script through shellcheck and see what it has to say. |
Quote:
"$@" preserves the arguments like "$1" "$2" "$3" With echo you hardly see a difference but with prinf "%s\n" you see it. Compare with plain arguments like Code:
echo aa bb cc in its arguments there is a $variable not wrapped in "quotes"? |
I'm not using $@ because it will take a long command and make it 9 different lines, but when using $* it stays in one line.
Here is the function to better get an understanding of where the issue may be. Works great except for not preserving quotes. If I edit the .note file and put the quotes in manually on a line I can recall it with no issue so far. Code:
#!/bin/bash shellcheck.net didn't have any issues to bring up regarding this. |
Quote:
Also I really recommend shellcheck for this - or any - shell script. |
Quotes are interpreted by bash and are not stored in command line arguments or variable values. This is why it works from the shell but not from a script.
You can find several threads on the same problem with lots of suggestions. If your actually trying to pass an entire rsync command what you are trying to do does not sound trivial. |
This is the line I've been testing since has a lot of quotes redirecting to a file. I'm using printf in function since it's built into bash, but have used echo and get same exact results and will keep using echo in this example.
> echo 'fzf --ansi --header="ctrl-e:Editor ctrl-l:Less enter:bat" --bind "ctrl-e:execute($EDITOR {})" --bind "ctrl-l:execute(less -Rf {})" --bind "enter:execute(bat --color=always {} || less -Rf {})" --preview-window=right:80% --preview "(bat -p --color=always --line-range 1:50 {} || head -50)" --color dark,hl:33,hl+:37,fg+:235,bg+:136,fg+:254 --color info:254,prompt:37,spinner:108,pointer:235,marker:235' >> file.txt When run from the shell using echo 'command' this works fine and will preserve all the "quotes" in the line redirecting to text file. If I run the same exact command, but within a bash script it doesn't preserve the "quotes" and they are all gone which I understand the reason why, but looking how to get around it. I've tried escaping the single quotes echo \' $* \' but redirects actual $* to file instead of command. If I use "$@" it will redirect the command to 8 different lines in the text file while not preserving the quotes. When I use "$*" it will put the entire command on one line which I want, but still won't preserve the quotes. Tried not quoting the variables and I get same results. The point of the function is to be able to add notes or commands to a file and recall it using the line number of the text file. When working on projects and running a lot of commands for testing I want to be able to do > note !! and have it put that last command in text file so later I can rerun it easily later like a bookmark doing > note 1 or whatever line number I want to run. Function works except for preserving quotes which breaks the command when recalling it. If command has not quotes then I can recall it just fine (like htop --help for example). I've tried print '%q' makes it worse with backslashes all over the command and still no quotes. Tried a loop using $@ to restructure the command to one line, but haven't gotten that working and it still removes the quotes when done inside the script. |
How about ${*@Q}?
|
Yes, as cited $@ is better to use.
Do realize it gives you a list, but you can concatenate that list easily. Suggest you post some code and results, to be more clear about your problem and continued responses that you feel the standard solutions are not suitable. It isn't in the best interest of everyone here to incrementally query and contend with each new flavor of this project's challenges. Instead you should give some background and cite technical reasons why there are things blocking you. I would suggest that being open to alternative solutions you may have rejected or not yet tried, may cause you to lose out on opportunities to solve this fairly fast and thus move ahead to your next challenge. |
Quote:
|
Quote:
You make it seem like I asked a one line question and never tried to give any other information or try new things. How else you supposed to solve an issue without incremental help? I'll mark this solved to make you happy. |
Quote:
As noted by Ondoho, this appears to be solely for the print statement. A test script shows that you can use $@, just that the print needs to be broken up somewhat: Code:
#!/bin/bash Code:
$ test-print.sh 1 2 3 4 5 The arguments to the script are accessible using both of these conventions, and the suggestion was to try and illustrate why or where they were specifically a problem. Since all that has been shown is that the print statement becomes complicated if you use it there, then it's rather difficult for us to advise how better to craft your script. Were you attempting to use the $@ somewhere else and did not find that it was suitable for you? |
Quote:
Thank you I appreciate the apologies. Using your advice I was able to get $@ to stay on one line (only reason I was using $*) after I removed the \n from the printf statement. Seems it was returning after every quoted break or space with \n which makes sense with $@. Thank you for that. Still doesn't preserve quotes, but I will use $@ going forward since it's staying one complete line now. Even when $@ was breaking on separate lines it wasn't preserving quotes within the command. If I use %q Code:
printf "%q " "$@" >> ~/.note Only time this works properly is if I do it straight from the shell, but when same command is in script, it doesn't preserve quotes. Code:
printf "%s" 'fzf --ansi --header="ctrl-e:Editor ctrl-l:Less enter:bat" --bind "ctrl-e:execute($EDITOR {})" --bind "ctrl-l:execute(less -Rf {})" --bind "enter:execute(bat --color=always {} || less -Rf {})" --preview-window=right:80% --preview "(bat -p --color=always --line-range 1:50 {} || head -50)" --color dark,hl:33,hl+:37,fg+:235,bg+:136,fg+:254 --color info:254,prompt:37,spinner:108,pointer:235,marker:235' >> ~/.note Playing around with older suggestions as maybe those will work now. Will post back later after more testing, but further than where I was before. Damn \n ruining my entire day. lol |
Unless someone else understands the shell far better, I do not believe you can get away with this, unless you escape the quotes when calling the script.
Reason being is that the arguments do not enter the script with quotes. If I'm to understand correctly, you are calling a script and placing single or double quotes around strings, a.k.a. arguments. Well, another test would be to do the following: Code:
#!/bin/bash Code:
$ test-print.sh 1 2 3 '4' 5 |
I'm going to say this is something that cannot be done in bash. I've tried a lot of combinations which give results of the command, but always without quotes no matter the pattern. Only if single quoted from the shell prompt itself.
This is what I've ended up using in the function: Code:
printf '%q ' "$@" >> "${notefile}"; printf '\n' >> "${notefile}" Code:
printf '%s ' ${*@Q} >> "${notefile}" |
All times are GMT -5. The time now is 10:48 AM. |