[SOLVED] Bash brainteaser: get raw string from command line [no parameter expansion]
SlackwareThis Forum is for the discussion of Slackware Linux.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Bash brainteaser: get raw string from command line [no parameter expansion]
Hello All
This is not strictly a Slackware issue and mods might want to move this post.
Is it possible to access the raw string that a user typed into the command line after the program/script name without any form of globbing or parameter expansion so that the 'special characters' are not special until <newline>?
I'm trying to write a script/program called notes that will be invoked as below in a terminal
Code:
notes "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
and append this one line entry in a file (.notes say)
Code:
20171021183845 "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
The nearest I can get to on the Interwebs is this page
This way only \ (and newline) cannot be catched (all the other characters worked for me) but I think they are processed by the shell before anything else, so you cannot avoid that.
You need to write c code to catch every keypress.
This is as close as i can get. Wrote a simple c program ("printarg.c) to echo the command line argument, and had to follow the exclamation point with a blank space.
Code:
printarg "\"That's impossible\! \", he said, as well as invoking the \$PATH variable and 'hinting' avidly"
Whatever you type on that command line is first going to be processed by the shell, which will do its own handling of quoting, variable expansion, and other special characters. There is nothing you can do in the script to reverse that and get back exactly what was typed. What you can do is invoke the script with no argument, and then within the script use the read command to read the line. Appending that line literally to the file is then not a problem.
But I'd rather use the "read" builtin instead as mentioned by others here, if your intention is to write a note. Less headaches not having to think how to quote something.
Yes, you are (all) correct. Can't get the raw keypresses using native bash commands on the command line.
I'm going to have to accept either typing escape codes in the notes or going for multi-line input of some kind. Looks like I'm going down rknichols' line.
Thanks. I'll leave the brain teaser up for a bit to see if anyone comes up with something amazing.
Diantre has hit the nail on the head: I was trying to 'suspend' any form of parameter expansion/globbing so as to keep typing easier.
Last edited by keithpeter; 10-21-2017 at 02:24 PM.
Distribution: Slackware64 15.0 (started with 13.37). Testing -current in a spare partition.
Posts: 928
Rep:
The command line goes to bash history as it is typed. Does this help?
Code:
$ echo "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
That's impossible! he said, as well as invoking the /usr/local/bin:/usr/bin:/bin:/usr/games:/usr/lib64/kde4/libexec:/usr/lib64/java/bin:/usr/lib64/java/jre/bin:/scripts:/usr/lib64/qt/bin variable and hinting avidly
$ history 2
510 echo "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
511 history 2
I see here a very important issue: echo will not give you the content of the variable, it will be immediately evaluated (before printing).
For example echo $VAR will print the value of VAR, echo * will print the files in the current directory. If you want to print the content of the variable, use ": echo "$VAR" will probably do what you want.
From the other hand you want to assign a value. If you want input use read as I posted before. If you want to assign, use ' again:
Code:
a='"That'"'"'s impossible!" he said, as well as invoking the $PATH variable and '"'"'hinting'"'"' avidly'
only the original ' should be tricked by: ' " ' " ' .
EDIT: Thanks to Paulo2 for the ~/.bash_history trick ! I'll try to remember that one !!
You didn't mention whether your notes app needed to be scriptable or not ...
I don't know offhand how to write a scriptable script that can 'reach upstream' and turn off bash input processing for it's own commandline ...
However, if your notes app can be an interactive app then this might work with a little work.
Save the following as say, notes.sh ...
Code:
#!/bin/sh
NoteFile="/tmp/notes.txt" # edit me ...
echo -e "\ntype your notes ; then press [Ctrl] D to exit\n" >&2
cat | \
gawk '
BEGIN {
Time = strftime( "%Y%m%d%H%M%S" ) " "
}
# main
{
print Time $0
}' >> $NoteFile
Usage:
Code:
notes.sh # press Enter
type your notes ... # when done, press {Ctrl] D ( aka eof )
What did we get ?
Code:
$ cat /tmp/notes.txt
20171022054632 "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
20171022054654 "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
You can use your mouse to cut-n-paste text into the `cat` input stream ( as I did ).
Sorry, best I can do
-- kjh
Last edited by kjhambrick; 10-22-2017 at 06:12 AM.
Reason: add p,s, about Paulo2's ~/.bash_history trick
However, if your notes app can be an interactive app then this might work with a little work.
...
-- kjh
Thanks very much, I shall have a play. The original concept was to type the command and then the note on one command line using the line editing commands that bash provides. The nearest thing looks like the read command used interactively as you say. Your conditioning of the text input is educational and I'll dig into awk/sed a bit more
I see here a very important issue: echo will not give you the content of the variable, it will be immediately evaluated (before printing).
For example echo $VAR will print the value of VAR, echo * will print the files in the current directory. If you want to print the content of the variable, use ": echo "$VAR" will probably do what you want.
From the other hand you want to assign a value. If you want input use read as I posted before. If you want to assign, use ' again:
Code:
a='"That'"'"'s impossible!" he said, as well as invoking the $PATH variable and '"'"'hinting'"'"' avidly'
only the original ' should be tricked by: ' " ' " ' .
Thanks pan64. Your read based solution is the one currently in use.
The idea was to avoid possible random behaviour by accidently typing commands in the text of a note! Remembering the escape sequences correctly could be tricky when in a hurry.
I have three solutions to try now so marking this as solved. Thanks all, very educational.
Relying on bash history is ingenious but likely to be fragile. I'd stick with reading from stdin if I were you.
Quote:
This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.
The following sequence works but only if you either source notes.sh ( or type: . notes.sh )
Paulo2's hint about the history command does do the deed ( ! thanks again Paulo2 ! )
Here is a session ( I did it twice to see it work )
Code:
$ echo "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
That's impossible! he said, as well as invoking the /home/local/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/usr/games:/root/bin:/usr/lib64/java/bin:/usr/lib64/kde4/libexec:/usr/lib64/qt/bin:/usr/lib64/qt5/bin:/usr/share/texmf/bin variable and hinting avidly
$ . notes.sh # note the dot-space invocation ( i.e. be sure to source /tmp/motes.sh into bash )
$ cat /tmp/notes.sh
20171022064629 echo "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
20171022064654 echo "That's impossible!" he said, as well as invoking the $PATH variable and 'hinting' avidly
-- kjh
this is /tnp/notes.sh
Code:
#!/bin/sh
#
# notes.sh - appends the preceeding commandline into $NoteFile
#
# source the script ( . notes.sh -or- source notes.sh )
NoteFile="/tmp/notes.txt" # edit me ...
history 2 |
gawk '
BEGIN {
Time = strftime( "%Y%m%d%H%M%S" ) " "
}
# main
{
Cmd = $0
gsub( /^ *[0-9]* */, "", Cmd )
print Time Cmd
exit( 0 ) # print the first line only ( skip the history cmd at eof )
}' >> $NoteFile
return 0 2>/dev/null || exit 0
I see here a very important issue: echo will not give you the content of the variable, it will be immediately evaluated (before printing).
For example echo $VAR will print the value of VAR, echo * will print the files in the current directory. If you want to print the content of the variable, use ": echo "$VAR" will probably do what you want.
If you don't want variable expansion with echo use single quotes instead of double quotes (although, any quotes will prevent * from being expanded).
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.