Use multiple arguments stored in one variable in a command, in fish shell - fish

I want to pass a bunch of parameters, stored in a variable, to a built in command, in a fish shell script. For example, like this:
set params "-h -d 1"
du $params
I was hoping the above would be equivalent to
du -h -d 1
But, it is not. It results in an error: "du: illegal option --"
It does work if I just set params to -h or to -d 1 but not both.
The one workaround I found is to do
eval du $params
but this seems...wrong, excessive. Any cleaner way?

Just drop the quotes.
The reason something like this works in POSIX shells (like bash) is because of "word splitting". When you use an unquoted variable, the value is substituted and then split along the characters in the IFS variable (typically tab, newline and space).
In fish, just use an array to separate the elements in the first place. And as it happens, the only change needed is to remove the quotes:
set params -h -d 1
du $params

Related

Use perl to replace some string in file with complicated password

I want to use perl in a bash script to replace some string in a text file with other strings that may contain various special characters (passwords). The variables containig the special characters come from the environment, so I cannot know them.
For example
# pw comes from the environment and I cannot be sure about it's content
pw='%$&/|some!\!smart%(]password'
pw=${pw//:/\\:}
perl -p -e "s:PASSWORD:$pw:" <<< "my pw is: PASSWORD" # this would come from a text file
# yields: my pw is: %PASSWORD/|some!!smart%(]password
Here I use : as a delimiter and escape possible occurences before, which should prevent some errors. But executing this does show that this isn't even remotely working as expected, though. The bash expansion is still messing up the password.
Now my question is: How can I safely take some environment variable and place it somewhere else? What might be a better approach? I could of course replace and escape further characters in the unknown variable but how can I ever be sure if this is enough?
Using the proper ENV special variable:
pw='%$&/|some!\!smart%(]password'
export pw=${pw//:/\\:}
perl -pe 's:PASSWORD:$ENV{pw}:' <<< "my pw is: PASSWORD"

How to store the value of telnet->cmd in an attribute in perl script

I have been running
grep -n \"fixed-address $IP_Address\" /etc/dhcp3/dhcpd.conf | cut -d \":\" -f2"
inside telnet->cmd and I want to store the output in a variable. I got an output value of 1 when I tried, but the output value should be 916. Here is a part of my Perl script
my $dhcp_value = $telnet->cmd(
string => "grep -n \"fixed-address $IP_Address\" /etc/dhcp3/dhcpd.conf | cut -d \":\" -f2"
);
print "$dhcp_value\n";
Please let me know how to run grep -n command in $telnet->cmd
If you're using the Net::Telnet module, then the documentation for the cmd method says this
In a scalar context, the characters read from the remote side are discarded and 1 is returned on success
In a list context, just the output generated by the command is returned, one line per element.
So it looks like you need to apply list context to the cmd method call. You can either use an array, like the example in the documnentation, or you can just put your scalar variable in parentheses
What I think you need is this
Note that I have built the command stringf separately for clarity, and used alternative delimiters with qq{...} so as to avoid having to escape embedded double quotes
Note also that the return value from the cmd call will probably have newline characters at the end. chomp will remove these for you
my $cmd = qq{grep -n "fixed-address $IP_Address" /etc/dhcp3/dhcpd.conf | cut -d ":" -f2};
my ($dhcp_value) = $telnet->cmd(string => $cmd );
chomp $dhcp_value;
print "$dhcp_value\n";

Perl Variables in system()

I'm trying to access a series of webpages in perl and write them to a series of files. The code I have looks like this:
open IN , "AbsoluteFinalData.txt"; #Each line has a number and ID name separated by a tab.
while(my $line = <IN>){
chop $line; #removes newline at the end
my #first_split = split(/\t/, $line);
my $IDnum = $first_split[0];
my $Uniprot = $first_split[1];
system('Uniprot=$Uniprot; curl -o "$Uniprot.html" http://pfam.xfam.org/\protein/.$Uniprot'); #More stuff after
The program, however, is giving me fits when I try to call $Uniprot in system(). Is there any way to call a variable defined in the perl script using system()?
system('Uniprot=$Uniprot; curl -o "$Uniprot.html" http://pfam.xfam.org/\protein/.$Uniprot');
You use single quotes, which doesn't interpolate. The literal command:
Uniprot=$Uniprot; curl -o "$Uniprot.html" http://pfam.xfam.org/\protein/.$Uniprot
Is being executed.
You want to interpolate your variables, which means using double quotes (and escaping contained ones:)
system("Uniprot=$Uniprot; curl -o \"$Uniprot.html\" http://pfam.xfam.org/\protein/.$Uniprot");
Or the qq quote-like operator which functions like the double quote but avoids needing to escape contained double quotes:
system(qq(Uniprot=$Uniprot; curl -o "$Uniprot.html" http://pfam.xfam.org/\protein/.$Uniprot"));
Given that you're not relying on the system command to perform any shell interpretation or file I/O redirection, you can achieve everything you want safely like this:
system 'curl', '-o', "$Uniprot.html", "http://pfam.xfam.org/protein/.$Uniprot";
The "list" version of system is safer to use than the single string version because it prevents shell command injection attacks.
Note also the use of double quotes to enable Perl's own variable interpolation, and also that there's no need to create the shell local variable Uniprot=$Uniprot since it's not used by Curl and is only being used by you to attempt to perform variable interpolation yourself.
Perl only interpolates variables within double quotes ("..."), not single quotes ('...').
system("Uniprot=$Uniprot; curl -o \"$Uniprot.html\" http://pfam.xfam.org/\protein/.$Uniprot");
Will do the substitution you're looking for.

How to expand variable literally when calling perl from csh script?

Below is a csh script.
#! /bin/csh
set alpha=10\20\30;
set beta = $alpha.alpha;
perl -p -i.bak -e 's/gamma/'$beta'/' tmp;
The tmp file contains just the word gamma. After running tmp.csh, I expect 10\20\30.alpha in tmp, but it's now 102030.alpha.
How to preserve slashes in this situation?
Note: I wouldn't prefer changing definition of alpha variable, as it is used in the script else where where it needs to be in this format (10\20\30) only.
Thanks.
In csh, for your alpha assignment, the backslash is being taken to mean 'a literal 2 or 3'. In order to keep csh from doing this, the assignment needs to be enclosed in quotes.
#! /bin/csh
set alpha="10\20\30";
set beta = $alpha.alpha;
perl -p -i.bak -e 's/gamma/'$beta'/' tmp;
If in doubt, it's often helpful to 'echo' your variables out to see exactly what they contain. I don't understand your final note, as the 'alpha' variable is not equal to 10\20\30 the way you have it originally assigned.

Perl String Interpolation in Bash Command

I'm trying to use GNU Date to get the seconds between two dates. The reason I'm using GNU Date is for performance (in testing was 10x faster than Perl) for this purpose. However, one of my arguments is a perl variable. Like this:
my $b_row="2012-01-05 20:20:22";
my $exec =qx'CUR_DATE=`echo $(date +"%F %T")` ; echo $(($(date -d "$CUR_DATE" +%s)-$(date -d "$b_row" +%s)))';
The problem is that b_row is not being expanded. I've tried a couple different solutions (IPC::System::Simple) being one, tried adjusting the backticks etc. No success, any ideas how to do this appropriately? The main thing is I need to capture the output from the bash command.
Make it easier on yourself and do the minimum amount of work in the shell. This works for me:
my $b_row = '2012-01-05 20:20:22';
my $diff = qx(date -d "\$(date +'%F %T')" +%s) -
qx(date -d "$b_row" +%s);
Just be absolutely sure $b_row doesn't have any shell metacharacters in it.
That's because you use ' :
Using single-quote as a delimiter protects the command from
Perl's double-quote interpolation, passing it on to the shell
instead:
$perl_info = qx(ps $$); # that's Perl's $$
$shell_info = qx'ps $$'; # that's the new shell's $$
qx has the feature of letting you choose a convenient delimiter, including the option of whether to interpolate the string or not (by choosing ' as the delimiter). For this use case, sometimes you want interpolation and sometimes you don't, so qx (and backticks) may not be the right tool for the job.
readpipe is probably a better tool. Like the system EXPR command, it takes an arbitrary scalar as input, and you have all of Perl's tools at your disposal to construct that scalar. One way to do it is:
my $exec = readpipe
'CUR_DATE=`echo $(date +"%F %T")` ;' # interp not desired
. ' echo $(($(date -d "$CUR_DATE" +%s)-$(date -d "'
. qq/"$b_row"/ # now interp is desired
. ' +%s)))'; # interp not desired again