When I'm interacting with the shell or writing a bash script I can do:
somecmd "some
arg"
Say now that I want to do the same in vim command-line mode:
:!somecmd "some<Enter>arg"
obviously won't work: as soon as I press <Enter> the command is executed. But neither the following do:
:!somecmd "some<C-V><Enter>arg"
:!somecmd "some<C-V>x0Aarg"
The first one inserts a carriage return instead of a line feed, which is right. The second one will break the command in two, trying to execute somecmd "some<C-V> first and then arg", both of which fail miserably.
I guess I could work around this using some echo -e command substitution, or embedding $'\n', but is it possible to type it directly in vim's command-line? I don't fully understand why the "some<C-V>x0Aarg" form doesn't work while $'some\narg' does. Is vim parsing the string previously to shell evaluation?
Well, I've found the answer myself, but I'm leaving here for further reference anyway. The documentation of :! states:
A newline character ends {cmd}, what follows is interpreted as a following ":" command. However, if there is a backslash before the newline it is removed and {cmd} continues. It doesn't matter how many backslashes are before the newline, only one is removed.
So you (I) should type "some\<C-V>x0Aarg" instead of "some<C-V>x0Aarg".
Plus, I could have done it using the system() function instead of the :! command:
:call system("somecmd 'some<C-V>x0Aarg'")
Related
I'm trying to write a regex string in the terminal but zsh is interpreting this regex instead of just printing it. My shell code:
echo "((https?:\/\/(?:www\.|(?!www)))?[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})"
Current output:
zsh: event not found: www)))?[a
I already tried to use simple quotes, double quotes and no quotes.
If you type this command in a file and run as a script, it should be fine, unless you have explicitly enabled history expansion in your script. But then, you know what you are doing.
If you really literally hack such a huge command manually into an interactive shell, either turn off history expansion (by setopt nobanghist), or prefix your ! by a \ (unless the ! is already between single-quotes).
Example: Typing echo !www won't work, but typing echo \!www will.
If you never use history expansion, turning it off permanently would probably be the best choice.
when I use zsh, exec this command as follow
$ echo "\`"
preexec: parse error
`
if change back bash, it's OK.
preexec is a hook that runs before the command: "pre-exec"ution. My hunch is you've got some prompt or zsh framework like oh-my-zsh that is choking on "`" character.
preexec
Executed just after a command has been read and is about to be
executed. If the history mechanism is active (and the line was not
discarded from the history buffer), the string that the user typed is
passed as the first argument, otherwise it is an empty string. The
actual command that will be executed (including expanded aliases) is
passed in two different forms: the second argument is a single-line,
size-limited version of the command (with things like function bodies
elided); the third argument contains the full text that is being
executed.
This seems like it should be simple, but I'm pulling out my remaining hair trying to get it to work. In a shell script I want to run some Applescript code that defines a string, then pass that string (containing a single quote) to a shell command that calls PHP's addslashes function, to return a string with that single quote escaped properly.
Here's the code I have so far - it's returning a syntax error.
STRING=$(osascript -- - <<'EOF'
set s to "It's me"
return "['test'=>'" & (do shell script "php -r 'echo addslashes(\"" & s & "\");") & "']"
EOF)
echo -e $STRING
It's supposed to return this:
['test'=>'It\'s me']
First, when asking a question like this, please include what's happening, not just what you're trying to do. When I try this, I get:
42:99: execution error: sh: -c: line 0: unexpected EOF while looking for matchin
sh: -c: line 1: syntax error: unexpected end of file (2)
(which is actually two error messages, with one partly overwriting the other.) Is that what you're getting?
If it is, the problem is that the inner shell command you're creating has quoting issues. Take a look at the AppleScript snippet that tries to run a shell command:
do shell script "php -r 'echo addslashes(\"" & s & "\");"
Since s is set to It's me, this runs the shell command:
php -r 'echo addslashes("It's me");
Which has the problem that the apostrophe in It's me is acting as a close-quote for the string that starts 'echo .... After that, the double-quote in me"); is seen as opening a new quoted string, which doesn't get closed before the end of the "file", causing the unexpected EOF problem.
The underlying problem is that you're trying to pass a string from AppleScript to shell to php... but each of those has its own rules for parsing strings (with different ideas about how quoting and escaping work). Worse, it looks like you're doing this so you can get an escaped string (following which set of escaping rules?) to pass to something else... This way lies madness.
I'm not sure what the real goal is here, but there has to be a better way; something that doesn't involve a game of telephone with players that all speak different languages. If not, you're pretty much doomed.
BTW, there are a few other dubious shell-scripting practices in the script:
Don't use all-caps variable named in shell scripts. There are a bunch of all-caps variables that have special meanings, and if you accidentally use one of those for something else, weird results can happen.
Put double-quotes around all variable references in scripts, to avoid them getting split into multiple "words" and/or expanded as shell wildcards. For example, if the variable string was set to "['test'=>'It\'s-me']", and you happened to have files named "t" and "m" in the current directory, echo -e $string will print "m t" because those are the files that match the [] pattern.
Don't use echo with options and/or to print strings that might contain escapes, since different versions treat these things differently. Some versions, for example, will print the "-e" as part of the output string. Use printf instead. The first argument to printf is a format string that tells it how to format all of the rest of the arguments. To emulate echo -e "$string" in a more reliable form, use printf '%b\n' "$string".
To complement Gordon Davisson's helpful answer with a pragmatic solution:
Shell strings cannot contain \0 (NUL) characters, but the following sed command emulates all other escaping that PHP's (oddly named) addslashes PHP function performs (\-escaping ', " and \ instances):
string=$(osascript <<'EOF'
set s to "It's me\\you and we got 3\" of rain."
return "['test'=>'" & (do shell script "sed 's/[\"\\\\'\\'']/\\\\&/g' <<<" & quoted form of s) & "']"
EOF
)
printf '%s\n' "$string"
yields
['test'=>'It\'s me\\you and we got 3\" of rain.']
Note the use of quoted form of, which is crucial for passing a string from AppleScript to a do shell script shell command with proper quoting.
Also note how the closing here-doc delimiter, EOF, is on its own line to ensure that it is properly recognized (in Bash 3.2.57, as used on macOS 10.12, (also when called as /bin/sh, which is what do shell script does), this isn't strictly necessary, but Bash 4.x would rightfully complain about EOF) with warning: here-document at line <n> delimited by end-of-file (wanted 'EOF')
If a single ` is entered in a command in bash or powershell, it enters a mode displaying >> on the prompt. What is this mode and what is it used for?
I typed cd ` instead of cd ~ and entered the mode. The only input that seemed to affect it was ctrl+c to terminate the command. I haven't been able to find anything regarding this searching the bash man pages or reference manual.
In bash/sh the ` character starts Command Substitution.
When you didn't finish the command (with another ` character) the shell realizes your command is unfinished and attempts to prompt you for more (using the value of $PS2).
Finish the command and hit enter and the entire thing will run.
The same thing is true for unfinished strings (` and ") as well.
In powershell I believe ` is line continuation. (Similar to \ in shell scripts and the like.)
As requested I am moving my comment to an answer to address the PowerShell side of the question.
In PowerShell the backtick ` is the Escape character. For the purposes of the OP's question, and incurring a >> prompt, the backtick ` is escaping the New Line and forcing the command interpreter to continue the current command on to the next line. So when the last character in the line is a ` it functions as Etan suggested as a line continuation character. When he hit Enter immediately after the backtick it gave the >> expecting him to finish the current command he was working on.
If not the last character it escapes whatever it precedes, allowing people to escape quotes within quotes, or state variable names within double quotes without string interpolation.
The >> prompt is, as explained in other answers, the host waiting for you to complete something. Be it a command, a string, a scriptblock, or a loop or some such.
(thank you Etan for indirectly showing me how the ` thing is done btw, that's kind of awesome for answering things here)
Edit: Bah, Keith Hill wandered in and helped me stick my foot in my mouth. I'll stand by my answer, as I believe it to be functionally correct (if not technically thorough), but evidently it is referred to as the line continuation character in documentation.
A backtick (`) begins a quote context and will keep reading until ended with another matching `. This mode is entered/continued when a quote is not completed on the current line (e.g. when enter is pressed).
Unlike with the ' and " quote contexts it also expects inner (' and ") quotes to be terminated correctly before it will terminate the ">>" context. (It actually doesn't matter that this mode is entered, that is just the shell saying that the expression has not been correctly terminated when run interactively.)
Consider this terminating input (it runs uname, capturing the output, and then displays it with echo):
echo "Hello " `
uname -m` ", you are awesome!"
And this this non-terminating (as the inner " is not closed) input:
echo `
echo "Hello world
`
And with standard (non-substitution quotes):
echo "Hello
word `"
Okay, I am sure this is simple but it is driving me nuts. I recently went to work on a program where I have had to step back in time a bit and use Redhat 9. When I'm typing on the command line from a standard xterm running KornShell (ksh), and I reach the end of the line the screen slides to the right (cutting off the left side of my command) instead of wrapping the text around to a new line. This makes things difficult for me because I can't easily copy and paste from the previous command straight from the command line. I have to look at the history and paste the command from there. In case you are wondering, I do a lot of command-line awk scripts that cause the line to get quite long.
Is there a way to force the command line to wrap instead of shifting visibility to the right side of the command I am typing?
I have poured through man page options with no luck.
I'm running:
XFree86 4.2.99.903(174)
KSH 5.2.14.
Thanks.
Did you do man ksh?
You want to do a set -o multiline.
Excerpt from man ksh:
multiline:
The built-in editors will use multiple lines on the screen for
lines that are longer than the width of the screen. This may not
work for all terminals.
eval $(resize) should do it.
If possible, try to break the command down to multiple lines by adding \
ie:
$ mycommand -a foo \
-f bar \
-c dif
The simple answer is:
$ set -o multiline
ksh earlier than 5.12, like the ksh shipped with NetBSD 6.1, doesn't have this option. You will have to turn off current Interactive Input Line Editing mode, which is usually emacs:
$ set +o emacs
This turns off a lot of featuers altogether, like tab-completion or the use of 'Up-arrow' key to roll back the previous command.
If you decide to get used to emacs mode somehow, remember ^a goes to the begining of the line ("Home" key won't workk) and ^e goes to the end.
I don't know of a way of forcing the shell to wrap, but I would ask why you'd be writing lines that long. With awk scripts, I simply wrap the script in single quotes, and then break the lines where I want. It only gets tricky if you need single quotes in the script -- and diabolical if you need both single and double quotes. Actually, the rule is simple enough: use single quotes to wrap the whole script, and when you want a single quote in the script, write '\''. The first quote terminates the previous single-quoted string; the backslash-single quote yields a single quote; and the last single quote starts a new single quoted string. It really gets hairy if you need to escape those characters for an eval or something similar.
The other question is - why not launch into an editor. Since I'm a die-hard vim nutcase (ok - I've been using vi for over 20 years, so it is easier for me than the alternatives), I have Korn shell set to vi mode (set -o vi), and can do escape-v to launch the editor on whatever I've typed.
This is kind of a pragmatic answer, but when that's an issue for me I usually do something like:
strings ~/.history | grep COMMAND
or
strings ~/.history | tail
(The history file has a little bit of binary data in it, hence 'strings')