Consider this dummy Windows batch script:
echo %1
Supposed just to echo to the terminal its first argument.
Assume its path in resp. Windows, Cygwin style is:
c:\test\win.bat
/cygdrive/c/test/win.bat
From Cygwin bash:
$ c:\test\win.bat "hello world"
"hello world"
So quotes correctly identify a single argument.
But now let us introduce spaces in path:
"c:\te st\win.bat"
/cygdrive/c/te\ st/win.bat
Then:
$ /cygdrive/c/te\ st/win.bat "hello world"
Gives:
"C:\te" is not recognized as an internal or external command, operable program or batch file.
The same happens with:
$ "/cygdrive/c/te st/win.bat" "hello world"
It should be noted this:
$ /cygdrive/c/te\ st/win.bat "hello"
hello
That is hello is now passed to win.bat unquoted (and with "/cygdrive/c/te st/win.bat" "hello" either).
How can I have spaces both in the path and the argument?
$ echo "echo %~1" > /cygdrive/c/te\ st/win.bat
$ cat /cygdrive/c/te\ st/win.bat
echo %~1
$ cmd /c $(echo "c:\te st\win.bat"| sed 's/ /^ /g') "aaa bbb"
C:\Users\Me>echo aaa bbb
aaa bbb
Related
A test file has the following string:
$ cat testfile
x is a \xtest string
The following script attempts to replace escape sequence: \x occurrences with yy using sed
#!/bin/bash
echo "Printing directly to stdout"
sed -e "s/\\\x/yy/g" testfile
var1=`sed -e "s/\\\x/yy/g" testfile`
echo "Printing from variable"
echo "${var1}"
As it can be seen below, the results are different when it is printed with and without saving to a temporary variable. Could someone help me understand why this happens?
I'd want the variable to hold the string that has replaced only \x
Printing directly to stdout
x is a yytest string
Printing from variable
yy is a \yytest string
Platform: macOS
You should put your command inside a $(...) like that:
#!/bin/bash
echo "Printing directly to stdout"
sed -e "s/\\\x/yy/g" testfile
var1=$(sed -e "s/\\\x/yy/g" testfile)
echo "Printing from variable"
echo "${var1}"
I found out today that I can write !$ to get the last argument from the last command executed.
Now I'm trying to create an alias using that shortcut and it isn't working at all.
These are the ones I'm trying to create.
alias gal='git add !$'
alias gcl='git checkout !$'
alias sl='sublime !$'
And this is the result output when calling gal or gcl
fatal: pathspec '!$' did not match any files
So it seems like !$ just isn't being replaced by the last argument from the last command in this context.
Is it possible?
Instead of fiddling with Bash's history, you might as well want to use Bash's $_ internal variable: The relevant part of the manual states:
$_: […] expands to the last argument to the previous command, after expansion. […]
For example:
$ touch one two three
$ echo "$_"
three
$ ls
$ echo "$_"
ls
$ a='hello world'
$ echo $a
hello world
$ echo "$_"
world
$ echo "$a"
hello world
$ echo "$_"
hello world
$
In your case, your aliases would look like:
alias gal='git add "$_"'
alias gcl='git checkout "$_"'
alias sl='sublime "$_"'
You can use the bash builtin history command fc: an example
$ alias re_echo='echo $(fc -ln -2 | awk '\''NR==1 {print $NF}'\'')'
$ echo foo
foo
$ re_echo bar
foo bar
$ re_echo baz
bar baz
$ re_echo qux
baz qux
I'm trying to cat some files together, while at the same time adding some text between files. I'm a Unix newbie and I don't have the hang of the syntax.
Here's my failed attempt:
cat echo "# Final version (reflecting my edits)\n\n" final.md echo "\n\n# The changes I made\n\n" edit.md echo "\n\n#Your original version\n\n" original.md > combined.md
How do I fix this? Should I be using pipes or something?
A process substitution seems to work:
$ cat <(echo 'FOO') foo.txt <(echo 'BAR') bar.txt
FOO
foo
BAR
bar
You can also use command substitution inside a here-document.
$ cat <<EOF
FOO
$(< foo.txt)
BAR
$(< bar.txt)
EOF
Use a command group to merge the output into one stream:
{
echo -e "# Final version (reflecting my edits)\n\n"
cat final.md
echo -e "\n\n# The changes I made\n\n"
cat edit.md
echo -e "\n\n#Your original version\n\n"
cat original.md
} > combined.md
There are tricks you can play with process substitution and command substitution (see Lev Levitsky's answer) to do it all with one command (instead of the separate cat processes used here), but this should be efficient enough with so few files.
If I understand you, it should be something like:
echo "# Final version (reflecting my edits)\n\n" >> combined.md
cat final.md >> combined.md
echo "\n\n# The changes I made\n\n" >> combined.md
cat edit.md >> combined.md
And so on.
How to run a command after assigning it to some variable in shell scripting?
example:
command_name=echo
Now, is there a way to use "$command_name hello world" instead of "echo hello world" ?
Yes. That exact code ($command_name hello world) will work.
Make sure that quotes, if present, are placed only around the command name and each individual argument. If quotes are placed around the entire string, it will interpret the entire string as the command name, which isn't what you want.
For example:
command_name="echo"
$command_name hello world
will be interpreted as:
echo hello world
(which works), whereas:
command_name="echo"
"$command_name hello world"
is interpreted as:
"echo hello world"
which doesn't work because it's trying to find a command called echo hello world rather than interpreting hello and world as arguments.
Similarly,
command_name="echo hello world"
"$command_name"
fails for the same reason, whereas:
command_name="echo hello world"
$command_name
works.
command_name='echo'
$command_name "Hello World"
#!/bin/bash
var="command"
"$var"
worked for me in script file
You can use eval for this:
Suppose you have an input_file that has the following:
a b c d e f g
Now try in your terminal:
# this sed command coalesces white spaces
text='sed "s/ \+/ /g" input_file'
echo $text
sed "s/ \+/ /g" input_file
eval $text
a b c d e f g
With bash arrays (which is the best practice when you have arguments):
commandline=( "echo" "Hello world" )
"${commandline[#]}"
I need to write a bash script that prints out its command line arguments in sorted order, one per line.
I wrote this script and it works fine, but is there any other way? Especially without outputting it to a file and sorting.
#!/bin/bash
for var in $*
do
echo $var >> file
done
sort file
rm file
Test run of the program:
$ script hello goodbye zzz aa
aa
goodbye
hello
zzz
You can pipe the for-loop to sort, or just do
printf '%s\n' "$#" | sort
#!/bin/bash
for var in "$#"; do
echo "$var"
done | sort
You want to use $# in quotes (instead of $*) to accommodate arguments with spaces, such as
script hello "goodbye, cruel world"
The pipe gets rid of the need for a temporary file.