I am wanting to pass a string variable in a ssh command. You can see in the code below I ssh to a server then cd to a directory that I pass a variable to. (cd $orig)
The variable is pulled from a file that I read in and put into an array.
I think that is where my error is because there might be unwanted hidden characters after I used the split command to read in from the file.
Here is the error I get:
ksh: /OnSight/jetplan/scripts/release/jscripts^M: not found
Can't open perl script "AddAlias.pl": No such file or directory
/OnSight/users/onsadm
SSHing to densbp53
/OnSight//scripts/release/jscripts
It can't find my script because the CD to the folder fails.
Sometimes the error says that 'end of file' can't be found. Like I'm doing a CD command with a EOF hidden symbol.
And here is the code:
for(my $j=0; $j < $#servName+1; $j++)
{
print "\nSSHing to $servName[$j]\n\n";
my $orig = $scriptfileLoc[$j];
#my $chopped = chop($orig);
chop($orig);
chomp($orig);
print ("\n$orig\n");
$sshstart = `ssh $servName[$j] "cd $orig; pwd; perl AddAlias.pl $aliasName $aliasCommand $addperl $servProfileLoc[$j]"`;
print $sshstart;
}
It outputs the $orig variable and it looks fine after the chop and chomp. (Which I've done both by themselves and still got the same error) So I pass it in my SSH command and it doesnt work.
I have a server file that holds all the server information, and yes it looks repetative I know.
densbp40:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp41:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp42:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp43:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp50:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp51:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp52:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp53:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp60:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp61:/export/home/.profile:/OnSight/scripts/release/jscripts
densbp62:/export/home/.profile:/OnSight/scripts/release/jscripts
tulsbp40:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp41:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp42:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp43:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp50:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp51:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp52:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
tulsbp53:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
densbcp1:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
densbcp2:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
densmsv1:/OnSight/.profile:/OnSight/scripts/jscripts
denamdp1:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
denamap1:/OnSight/users/profile:/OnSight/scripts/release/jscripts
denamap2:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
denfpev1:/OnSight/users/.profile:/OnSight/scripts/release/jscripts
This script asks the user to choose to send a file to ALL servers or just one.
To remove CR (^M) from the end of lines, use the following regex:
$orig =~ s/\r$//gm;
Anchoring at the line end guarantees that any other carriage return characters are not removed from your input. (You probably don't them there either, but to normalize line endings, it's better to not touch other characters).
g enables global matches (not only the first) and m enables multiline mode, so that $ matches the end of each line in a multiline string, not only the end of the string.
"^M" is carriage return a.k.a "\r". Use regex to remove it:
$orig =~ s/\r//g;
Related
For personal development and projects I work on, we use four spaces instead of tabs.
However, I need to use a heredoc, and I can't do so without breaking the indention flow.
The only working way to do this I can think of would be this:
usage() {
cat << ' EOF' | sed -e 's/^ //';
Hello, this is a cool program.
This should get unindented.
This code should stay indented:
something() {
echo It works, yo!;
}
That's all.
EOF
}
Is there a better way to do this?
Let me know if this belongs on the Unix/Linux Stack Exchange instead.
(If you are using bash 4, scroll to the end for what I think is the best combination of pure shell and readability.)
For heredocs, using tabs is not a matter of preference or style; it's how the language is defined.
usage () {
⟶# Lines between EOF are each indented with the same number of tabs
⟶# Spaces can follow the tabs for in-document indentation
⟶cat <<-EOF
⟶⟶Hello, this is a cool program.
⟶⟶This should get unindented.
⟶⟶This code should stay indented:
⟶⟶ something() {
⟶⟶ echo It works, yo!;
⟶⟶ }
⟶⟶That's all.
⟶EOF
}
Another option is to avoid a here document altogether, at the cost of having to use more quotes and line continuations:
usage () {
printf '%s\n' \
"Hello, this is a cool program." \
"This should get unindented." \
"This code should stay indented:" \
" something() {" \
" echo It works, yo!" \
" }" \
"That's all."
}
If you are willing to forego POSIX compatibility, you can use an array to avoid the explicit line continuations:
usage () {
message=(
"Hello, this is a cool program."
"This should get unindented."
"This code should stay indented:"
" something() {"
" echo It works, yo!"
" }"
"That's all."
)
printf '%s\n' "${message[#]}"
}
The following uses a here document again, but this time with bash 4's readarray command to populate an array. Parameter expansion takes care of removing a fixed number of spaces from the beginning of each lie.
usage () {
# No tabs necessary!
readarray message <<' EOF'
Hello, this is a cool program.
This should get unindented.
This code should stay indented:
something() {
echo It works, yo!;
}
That's all.
EOF
# Each line is indented an extra 8 spaces, so strip them
printf '%s' "${message[#]# }"
}
One last variation: you can use an extended pattern to simplify the parameter expansion. Instead of having to count how many spaces are used for indentation, simply end the indentation with a chosen non-space character, then match the fixed prefix. I use : . (The space following
the colon is for readability; it can be dropped with a minor change to the prefix pattern.)
(Also, as an aside, one drawback to your very nice trick of using a here-doc delimiter that starts with whitespace is that it prevents you from performing expansions inside the here-doc. If you wanted to do so, you'd have to either leave the delimiter unindented, or make one minor exception to your no-tab rule and use <<-EOF and a tab-indented closing delimiter.)
usage () {
# No tabs necessary!
closing="That's all"
readarray message <<EOF
: Hello, this is a cool program.
: This should get unindented.
: This code should stay indented:
: something() {
: echo It works, yo!;
: }
: $closing
EOF
shopt -s extglob
printf '%s' "${message[#]#+( ): }"
shopt -u extglob
}
geta() {
local _ref=$1
local -a _lines
local _i
local _leading_whitespace
local _len
IFS=$'\n' read -rd '' -a _lines ||:
_leading_whitespace=${_lines[0]%%[^[:space:]]*}
_len=${#_leading_whitespace}
for _i in "${!_lines[#]}"; do
printf -v "$_ref"[$_i] '%s' "${_lines[$_i]:$_len}"
done
}
gets() {
local _ref=$1
local -a _result
local IFS
geta _result
IFS=$'\n'
printf -v "$_ref" '%s' "${_result[*]}"
}
This is a slightly different approach which requires Bash 4.1 due to printf's assigning to array elements. (for prior versions, substitute the geta function below). It deals with arbitrary leading whitespace, not just a predetermined amount.
The first function, geta, reads from stdin, strips leading whitespace and returns the result in the array whose name was passed in.
The second, gets, does the same thing as geta but returns a single string with newlines intact (except the last).
If you pass in the name of an existing variable to geta, make sure it is already empty.
Invoke geta like so:
$ geta hello <<'EOS'
> hello
> there
>EOS
$ declare -p hello
declare -a hello='([0]="hello" [1]="there")'
gets:
$ unset -v hello
$ gets hello <<'EOS'
> hello
> there
> EOS
$ declare -p hello
declare -- hello="hello
there"
This approach should work for any combination of leading whitespace characters, so long as they are the same characters for all subsequent lines. The function strips the same number of characters from the front of each line, based on the number of leading whitespace characters in the first line.
The reason all the variables start with underscore is to minimize the chance of a name collision with the passed array name. You might want to rewrite this to prefix them with something even less likely to collide.
To use in OP's function:
gets usage_message <<'EOS'
Hello, this is a cool program.
This should get unindented.
This code should stay indented:
something() {
echo It works, yo!;
}
That's all.
EOS
usage() {
printf '%s\n' "$usage_message"
}
As mentioned, for Bash older than 4.1:
geta() {
local _ref=$1
local -a _lines
local _i
local _leading_whitespace
local _len
IFS=$'\n' read -rd '' -a _lines ||:
_leading_whitespace=${_lines[0]%%[^[:space:]]*}
_len=${#_leading_whitespace}
for _i in "${!_lines[#]}"; do
eval "$(printf '%s+=( "%s" )' "$_ref" "${_lines[$_i]:$_len}")"
done
}
funtion.bat echo variables
set "Var1=%1"
set "Var2=%2"
set "Var3=%3"
echo %Var1% %Var2% %Var3%
I use a batch that calls this function by passing 3 arguments
call function.bat blabla= argument2 TEST.txt
As you see my first argument has an equal sign in it. But I want to use it as a string and not as an operator.
When I run the batch this is the result that I get:
blabla
argument2
TEST.txt
This is the result that I want:
blabla=
argument2
TEST.txt
Does anyone have an idea of how to get "blabla="?
From cmd /? in cmd:
The special characters that require quotes are:
<space>
&()[]{}^=;!'+,~ `
As you can see, you should quote almost everything that contains = because it is used as a separator. You should run your batch file with the command:
call function.bat "blabla=" "argument2" "TEST.txt"
in cmd and then remove the double quotes for each argument using the following code (the ~ modifier):
set "Var1=%~1"
set "Var2=%~2"
set "Var3=%~3"
echo %Var1% %Var2% %Var3%
and it should work. This way is recommended for best practice. Do it always.
I have a file file.dat as follow:
1.1,2.1 1.4
3.1,2.1 2.4
2.4,4.5 11.5
..
And I want to select each time the whole line (string) and replace it in another file. So far I tried the following
#!/bin/csh
set FILENAME = 'file.dat' # file in which the strings are
set str = "229.8,230.9 230.36" # initialize the first string
set n = 1
while ( $n <= 3 ) # number of lines in the FILENAME
echo Testing the first string $str
set rep = $(head -n $n "$FILENAME")
# n++ # increment the index
end
When I tried to launch the script csh launch.sh I obtained the follow error message
Testing the first string 229.8,230.9 230.36
Illegal variable name. # connect with the rep definition(?)
The file in which I want to change the string str is as follow (this is btw a secondary problem which I could figure out by myself once I understand what's wrong in the first lines):
# Name Type Par
Mi FI 154.2355189465
So UN 229.8,230.9 230.36 # line to be changed
Za FI 0.8000020209
May somebody help me, please?
$(...) is Bash syntax for command substitution in Bash.
In C-shell you have to use backticks instead (yuck).
I have a bunch of directories to process, so I start a for loop like this:
foreach n (1 2 3 4 5 6 7 8)
Then I have a bunch of commands where I am copying over a few files from different places
cp file1 dir$n
cp file2 dir$n
but I have a couple commands where the $n is in the middle of the command like this:
cp -r dir$nstep1 dir$n
When I run this command, the shell complains that it cannot find the variable $nstep1. What i want to do is evaluate the $n first and then concatenate the text around it. I tried using `` and (), but neither of those work. How to do this in csh?
In this respect behavior is similar to POSIX shells:
cp -r "dir${n}step1" "dir${n}"
The quotes prevent string-splitting and glob expansion. To observe what this means, compare the following:
# prints "hello * cruel * world" on one line
set n=" * cruel * "
printf '%s\n' "hello${n}world"
...to this:
# prints "hello" on one line
# ...then a list of files in the current directory each on their own lines
# ...then "cruel" on another line
# ...then a list of files again
# ... and then "world"
set n=" * cruel * "
printf '%s\n' hello${n}world
In real-world cases, correct quoting can thus be the difference between deleting the oddly-named file you're trying to operate on, and deleting everything else in the directory as well.
I wrote simple script as follow
#!/bin/bash
auth_type=""
SM_Read-only="Yes"
SM_write-only="No"
echo -e ${SM_Read-only}
echo -e ${SM_Write-only}
if [ "${SM_Read-only}" == "Yes" ] && [ "${SM_Write-only}" == "Yes" ]
then
auth_type="Read Write"
else
auth_type="Read"
fi
echo -e $auth_type
And when i execute it i got following output with errors.
./script.bash: line 5: SM_Read-only=Yes: command not found
./script.bash: line 6: SM_write-only=No: command not found
only
only
Read
Any one know correct way to declare the variable with "-" (dash)?
EDIT:
have getting response from c code and evaluate the variables for example
RESP=`getValue SM_ Read-only ,Write-only 2>${ERR_DEV}`
RC=$?
eval "$RESP"
from above scripts code my c binary getValue know that script want Read-only and Write-only and return value to script.So during eval $RESP in cause error and in my script i access variable by
echo -e ${SM_Read-only}
echo -e ${SM_Write-only}
which also cause error.
Rename the variable name as follows:
SM_Read_only="Yes"
SM_write_only="No"
Please, don't use - minus sign in variable names in bash, please refer to the answer, on how to set the proper variable name in bash.
However if you generate the code, based on others output, you can simply process their output with sed:
RESP=$(getValue SM_ Read-rule,Write-rule 2>${ERR_DEV}|sed "s/-/_/g")
RC=$?
eval "$RESP"
- is not allowed in shell variable names. Only letters, numbers, and underscore, and the first character must be a letter or underscore.
I think you cant have a dash in your variables names, only letters, digits and "_"
Try:
SM_Read_only
Or
SM_ReadOnly