[ncftp]how to pass value to command into a bash script - bash

I have a bash script and I want to use ncftp to do something. if I have this:
#!/bin/sh
HOST='my_IP_FTP_HOST'
USER='username'
PASSWD='password'
ncftp -u $USER -p $PASSWD $HOST <<END_SCRIPT
pwd
quit
END_SCRIPT
I get this error:
Syntax error in parameters or arguments
I don't understand why.
If I give it only the value and not the variables it works...
if I launch
$ sh -x script.sh
I get:
+ HOST=$'xxx.x.xx.xx\r'
+ USER=$'username\r'
+ PASSWD=$'password\r'
+ ncftp -u $'username\r' -p $'password\r' $'xxx.x.xx.xx\r'
NcFTP 3.2.1 (Jul 29, 2007) by Mike Gleason (http://www.NcFTP.com/contact/).
Welcome to FTP server
Syntax error in parameters or arguments
hmmm.... \r creates problems sure.

Are you editing this file on Microsoft Windows? It doesn't works because the original file uses Windows carriage returns, which are passed to variables and then to ncftp, which then halts.
Fix it by using another text editor, or by using dos2unix. Ideally you'd first use dos2unix once and then change the text editor.
Alternatively (but really, really not recommended) you could just parse the variables and remove the extra \r, like below, especially when the problem arises at some input reading, which doesn't seems to be the case here.
HOST=${HOST%\\r}
USER=${USER%\\r}
PASSWD=${PASSWD%\\r}
Take care when copying text from Windows, or when editing without appropriate software.

Related

Here Document to interact with VI

I was just trying to figure out EOF and here documents. I read something online that seemed like a cool idea I could expand upon. It is supposed to create a text file, and add text to it, all using a here document. The syntax is as follows:
#!/bin/sh
filename=test.txt
vim $filename <<EndOfCommands
i
This file was created automatically from
a shell script.
^[
ZZ
EndOfCommands
Now unfortunately I get an error from this:
./EOF.sh
Vim: Warning: Input is not from a terminal
Vim: Error reading input, exiting...
Vim: Finished.
Can anyone help fix this error? Also im assuming ^[ stands for the escape button being hit?
vi and vim are meant to be used interactively in a terminal, not scripted.
Using ed instead, which can happily accept input from standard input sources of all types:
#!/bin/sh
filename=test.txt
ed -s "$filename" <<EndOfCommands
i
This file was created automatically from
a shell script.
.
w
EndOfCommands
(In insert mode, a line with a single period indicates end-of-input and goes back to command mode, kind of like escape in vi(m).)
Using ex is another option; on systems with vim installed it's often a non-visual version of it.
With vim:
filename="test.txt"
vim -c ":wq! $filename" - << EOF
This file was created automatically from
a shell script.
EOF
See: man vim

How do I edit current shell command without executing it?

There seems to be quite a lot of information on how to edit and execute a command using your editor using "edit-and-execute-command (C-x C-e)", but what I would like to achieve is take the current shell command, apply certain filtering (using a script) and then return it to prompt for further approval/manual changes before execution. Is this possible with bash?
Latest update based on my experience
The part 0"+y$dd in the following mapping is really something that you should carefully think about and tailor it to your taste/workflow/experience.
For instance, very frequently I've found myself ending up with multiple lines in the buffer, where I only want to execute the one the cursor is on; in this case I can use 0"+y$dd:%d<CR> instead of 0"+y$dd.
And this is just one of the possible scenarios.
Final answer for those who like vim
Set vim as your EDITOR/VISUAL, so that when editing a command line, you will use vim to edit it.
Put au BufEnter /tmp/bash-fc.* nn <Leader>d 0"+y$dd:wq<CR> in your ~/.vimrc file to map Leaderd (which you will rarely use when editing a command) to the action "delete the current line into the + register without the trailing EOL".
you can use either the + or the * register in the mapping above; the ways to paste into the terminal will likely differ; you need the +clipboard option for these registers to be available.
When finished editing a command in the vim editor, hit EscapeLeaderd.
Paste the clipboard into the terminal (this is terminal-dependent).
Original answer
I often need to do the same, and I do it as follows. (I normally use the set -o vi in bash, so points 1 and 2 in the following are different if you use set -o emacs, the default; based on your question it looks like points 1 and 2 are unified in Ctrl+x followed by Ctrl+e, which is harder to type, imho.)
hit Escape to be in normal mode,
hit v to enter the editor to edit the command,
edit the command as I like,
(This is where you ask the question.)
hit Escape0"+y$dd:wq,
Note: 0"+y$, not simply "+yy, as the latter would copy the newline too, and this would result in executing the command upon pasting it in the command line,
paste the clipboard on the command line
how to do this depends on the terminal you are using, I guess; I hit Ctrl+Alt+v in URxvt.
proceed to approval/manual edit.
Clearly this is just a workaround, consisting in copying the edited command into the clipboard before deleting the whole command, so that nothing gets executed upon exiting the editor; however it's the best I can get for myself.
Update
As my EDITOR (and VISUAL) is equal to vim, when I edit the command, I edit it in vim.
In this respect, I have noticed that the buffer is named /tmp/bash-fc.random, where random is a 6-characters alphanumeric random string.
This gives space to a lot of possiblities, if you use vim as your editor, as you can define some mapping in your .vimrc to execute the whole sequence Escape0"+y$dd:wq. For instance, one command that you'd rarely use when editing a command line is Leaderd; therefore you can put the following mapping in your .vimrc file
au BufEnter /tmp/bash-fc.* nn <Leader>d 0"+y$dd:wq<CR>
so that step 4 in the above recipe becomes
hit EscapeLeaderd
It's not possible to do that in Bash/readline but it's possible in zsh
using edit-command-line command:
darkstar% autoload edit-command-line; zle -N edit-command-line
darkstar% bindkey "^X^E" edit-command-line
Now press Control-x Control-e to open your editor, edit line, leave the editor - you will see the updated command line but it will not be executed automatically.
Now that I think about it, maybe a variation of what #kenorb suggested in a comment is the best workaround (as it seems no solution exists), if we want to stick to bash.
What you can do is prepend a # (the comment character in bash) to the command, rather than echo. Then when you exit the editor, the command will be ineffective, and you will only have to press arrow up (or k, if you use set -o vi), remove the # and confirming.
Note that this strategy adds just a few keystrokes, so it can be fairly efficient, depending on your typing level.
These pieces might get you closer:
a) replace the the normal binding for newline newline (ctrl-M)
bind -x '"\C-M":date"
b) grab the current line from the history using !#
replace date with whatever script you want.
c) edit manually
d) if necessary, somehow tie in !!:p which prints the new command to the command line but does not execute it, thus letting you manually edit it.
e) using ctrl-J submit edited command rather than a newline
or they might not ....
There is an option in bash to modify command from history without executing it. I'm not sure it it's possible to use script for this, doesn't seem to be likely. Although, you can make modifications using history modifiers.
Enable option histverify to prevent execution of modified command
Use chain of modifiers to change last command
Use "!!" to put your result to command line for final edit
Here is how it looks:
$ shopt -s histverify
$ ls *.sh
script1.sh script2.sh script3.sh script-return.sh
$ !!:s/*/script1/:p
ls script1.sh
$ !!:s/1/2/:p
ls script2.sh
$ !!
$ ls script2.sh
script2.sh
I'd like to point you to the Composure framework for Bash (I'm not affiliated with it): https://github.com/erichs/composure
It provides draft and revise functions that sound like they could help with what you're trying to do. Here's a (long) quote from the project's readme file:
Composure helps by letting you quickly draft simple shell functions,
breaking down your long pipe filters and complex commands into
readable and reusable chunks.
Draft first, ask questions later
Once you've crafted your gem of a command, don't throw it away! Use
draft () and give it a good name. This stores your last command as a
function you can reuse later. Think of it like a rough draft.
$ cat servers.txt
bashful: up
doc: down
up-arrow
$ cat servers.txt | grep down
doc: down
$ draft finddown
$ finddown | mail -s "down server(s)" admin#here.com
Revise, revise, revise!
Now that you've got a minimal shell function, you may want to make it
better through refactoring and revision. Use the revise () command
to revise your shell function in your favorite editor.
generalize functions with input parameters
add or remove functionality
add supporting metadata for documentation
$ revise finddown
finddown ()
{
about finds servers marked 'down' in text file
group admin
cat $1 | grep down
}
$ finddown servers.txt
doc: down
It does not seem possible with a keyboard shortcut, at least:
$ bind -P | grep -e command -e edit
complete-command can be found on "\e!".
edit-and-execute-command can be found on "\C-x\C-e".
emacs-editing-mode is not bound to any keys
possible-command-completions can be found on "\C-x!".
vi-editing-mode is not bound to any keys
This can be done in native bash using readline specifically READLINE_LINE and READLINE_POINT variables. I use this functionality all the time though not through vim, you would need to get the value of $selected from your vim command and if not empty it takes your original line + your input and replaces your original line with the combination without executing. output as a variable
_main() {
selected="$(__coms_select__ "$#")"
origonal_text=$READLINE_LINE READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
}
bind -m emacs-standard -x '"\C-e": _main '
bind -m vi-command -x '"\C-e": _main '
bind -m vi-insert -x '"\C-e": _main '
Edit
Just remembered these two utilities that will let you do this as well.
Vipe allows you to run your editor in the middle of a unix pipeline and edit the data that is being piped between programs.
vp, up, vipe, Neomux (upgrade of nvim terminal) you can do some pretty neat throwing buffers between the terminal and split window.
and Athame (full vim on the command line)
https://github.com/ardagnir/athame
careful with that one though plugins work on the cli and it can get funky if you got tons of plugins

.sh output to .txt file - what am I doing wrong?

I am running Windows 10 and am trying to save the error output of a test.sh file to a text file.
So I created the test.sh file and wrote an unkown command in it (i.e. "blablubb").
After that I open the terminal (cmd.exe), switch to the directory and type test.sh 2>> log.txt.
Another window opens with "/usr/bin/bash --login -i \test.sh" in the title bar, shows me "bash: blablubb: command not found" and then closes immediately.
I want to save that output because the bash-window just opens for a split second. Every google search brings me to websites talking about redirecting the output and that Stream2 ist STDERR and therefore I should use test.sh 2>> log.txt or something smiliar that takes care of the STDERR stream.
If I try the same with a test.sh file and the content:
#!/bin/bash
echo hi there
I get the output in the briefly open bash-window:
bash: #!/bin/bash: No such file or directory
hi there
But the log.txt file is empty.
If I only have echo hi therein the test.sh file I get bash: echo: command not found in the bash-window.
The log.txt also empty.
If I type the following directly in the terminal, the output is written in the log.txt:
echo hi > log.txt 2>&1
If I type directly in the terminal:
echdo hi > log.txt 2>&1
I get 'Der Befehl "echdo" ist entweder falsch geschrieben oder konnte nicht gefunden werden.' in the log.txt file.
So I guess the redirecting of the output works fine until I use test.sh.
I know that .sh files are something from the unix world and that the problem might lie there but I don't know why I can not redirect the output briefly shown in the bash-console to a text file.
The 2>> redirection syntax only works if the command line containing that syntax is interpreted by bash. So it won't work from the Windows command prompt, even if the program you are running happens to be written in bash. By the time bash is running, it's too late; it gets the arguments as they were interpreted by CMD or whatever your Windows command interpreter is. (In this case, I'm guessing that means the shell script will find it has a command line argument [$1] with the value "2".)
If you open up a bash window (or just type bash in the command one) and then type the test.sh 2>>log.txt command line in that shell, it will put the error message in the file as you expect.
I think you could also do it in one step by typing bash -c "test.sh 2>>log.txt" at the Windows command prompt, but I'm not sure; Windows quoting is different than *nix quoting, and that may wind up passing literal quotation marks to bash, which won't work.
Note that CMD does have the 2>> syntax as well, and if you try to run a nonexistent windows command with 2>>errlog.txt, the "is not recognized" error message goes to the file. I think the problem comes from the fact that CMD and bash disagree on what "standard error" means, so redirecting the error output from Windows doesn't catch the error output by bash. But that's just speculation; I don't have a bash-on-Windows setup handy to test.
It would help to know if you are running Windows Subsystem for Linux (Beta). Or if you are doing something else. I'm assuming this is what you are doing on windows 10.
If this is the case are you using bash to run the script?
Are you using win-bash?
If it is win-bash I'm not very familiar and would recommend Windows Subsystem for Linux (Beta) for reasons like this. win-bash, while cool, might not be compatible with redirection operators like 2>>.
You have stdout and stderr, by default (if you don't specify) the >> (or append) will only append standard output into the txt file.
If you use 2 it will append the standard error into the txt file. Example: test.sh 2>> log.txt
This could be better described at this site.
To get exactly the command for append both stdout and stderr, go to this page.
Please tell me if this doesn't answer your question. Also, it could be more valuable to attempt a search for this answer first and explain why your search found nothing or give more extensive clarification as to what the problem is. I love answering questions and helping, but creating a new forum page for what might be an easy answer may be ineffective. I've had a bunch of fun with your question. I hope that I've helped.
That's makes a lot of sense. Thanks Mark!
Taking what mark says into account I would get Windows Subsystem for Linux (Beta). There are instructions here. Then run your script from there.

Find and replace with CGI script

I'm trying to use a CGI script to run a find and replace command on a specific text file.
I currently have a CGI script (foo.sh) which then executes a non-CGI shell script (bar.sh). In the non-CGI shell script (bar.sh), I'm able to perform a number of simple bash commands such as wget, mkdir and cd, and I'm also able to execute a .js file with the standard dot-slash bash syntax.
However, I can't get any find and replace commands to work when executed with CGI. I've tried sed, awk and perl, all of which work perfectly when used either directly on the command line or if I execute bar.sh from the command line. But once I try to execute the CGI script from the browser, the find and replace commands no longer work.
The syntax I've tried is below. Any suggestions appreciated.
sed -i 's/foo/bar/g' text.txt
{ rm text.txt && awk '{gsub("foo", "bar", $0); print}' > text.txt; } < text.txt
perl -p -i -e 's/foo/bar/g' text.txt
just a few thoughts:
if run by the web server, the script will probably be executed as a different user which could lead to permission-related problems.
maybe the awk/sed etc. commands are not in the path used by the web server process (try to use an absolute path here as well)
is there anything in the web server's error log?
Thanks for the input Michael, and sorry for the late response. You were correct in that it was a permissions issue caused by the fact that the CGI script runs not as me but as the "www-data" user.
The problem occurred because that user didn't have write privileges to execute a sed find and replace command on the target folder (in this case a directory within /usr/share/).
I changed permissions on the target folder to full read/write everyone, and now the script runs successfully.
Thanks again.

Simple shell script doesn't work like command line?

I'm trying to write a script that contains this
screen -S demo -d -m which should start a new screen session named demo and detach it.
Putting screen -S demo -d -m in the command line works.
If I put it in a file named boot.sh, and run it ./boot.sh I get
Error: Unknown option m
Why does this work in the command line but not as a shell script?
This file was transferred from windows and had ctrl-M characters.
Running "screen" on my Linux machine, a bad option (Screen version 4.00.03jw4 (FAU) 2-May-06) gives the error,
Error: Unknown option -z"
while your description includes no dash before the offending option. I'd check that the characters in your script file are what you expect them to be. There are many characters that look like a dash but which are not.
cat -v boot.sh
may show something interesting as it'll show codes for non-ascii characters.
This may seem a little like the "make sure your printer is plugged in" kind of help, but anyway:
have you tried to check if the screen you're invoking from the script is the same as the one invoked from the command line ?
I'm thinking you may change the PATH variable inside your script somewhere and perhaps screen from the script would be something else (a different version, perhaps ?).

Resources