What does $() do? - bash

Trying to troubleshoot this issue:
https://unix.stackexchange.com/questions/128894/ssh-exchange-identification-connection-closed-by-remote-host-not-using-hosts-d
and part of one solution is to use:
$(which sshd)
which in my case outputs:
Could not load host key: /etc/ssh_host_rsa_key
Could not load host key: /etc/ssh_host_dsa_key
I keep a cheat sheet for all my bash commands and wanted to add in:
$()
It appears to be doing something to the sshd executable.
Related
What does it mean in shell when we put a command inside dollar sign and parentheses: $(command)

$() is a way to execute another process and collect its output. See http://wiki.bash-hackers.org/syntax/expansion/cmdsubst for more details.
When such expression is passed to bash, its output gets executed. It effectively call the command using its full path, as that is what which returns. The messages printed are from sshd process started by that expression.
Note that which locates executable scanning $PATH, same as when you execute the command. In other words, executing which output it is not going to affect which executable is run, only the full path to executable tracked by operating system.

$(which sshd) will be replaced by the stdout resulting from running which sshd. which sshd will return the fully-qualified path of the executable invoked when invoking sshd:
which returns the pathnames of the files (or links) which would be executed in the current environment, had its arguments been
given as commands in a strictly POSIX-conformant shell. It does this by searching the PATH for executable files matching the
names of the arguments. It does not follow symbolic links.
Examples, as run on a command line, where > represents the input prompt:
COMMAND: which sshd
OUTPUT: /usr/sbin/sshd
COMMAND: echo "The full path of sshd is $(which sshd)"
OUTPUT: The full path of sshd is /usr/sbin/sshd
COMMAND: $(which sshd)
OUTPUT: [[whatever output you get from running /usr/sbin/sshd]]

Related

zsh: permission denied: /Users/myName

I am new to programming and I was trying to add the SSH key to my GitHub account (using mac interface). And when I was trying to copy the generated key using the command:
~ pbcopy < ~/testkey.pub
It was showing me this error
zsh: permission denied: /Users/myName
Someone please help me.
In a basic shell command, the first "word" is the name of the program to run (i.e. the name of the executable that'll actually perform the command). For example, if you run the command ls -l ~/testkey.pub, it actually runs a program named "ls" (probably in the /bin directory, so its full path is /bin/ls), and passes it the arguments "-l" and "/Users/myName/testkey.pub".
"Wait", I hear you say, "where'd that '/Users/myName' bit come from?" Well, ~ is shell shorthand for the path to your home directory, and when the shell sees it as part of a command (well, depending on the exact context), it'll replace it with the path to your home directory. Thus, ~/testkey.pub gets expanded to /Users/myName/testkey.pub. Try it with echo ~ and you'll see what I mean.
Now, when you try to run the command
~ pbcopy < ~/testkey.pub
the shell expands out the ~s, giving:
/Users/myName pbcopy < /Users/myName/testkey.pub
and since "/Users/myName" is the first word of this command, it tries to execute that as a program. But your home directory isn't an executable program, it's a directory, and you aren't allowed to execute directories, so you get a permissions error.
I'm pretty sure the ~ isn't actually supposed to be part of the command at all. I think you just want to run:
pbcopy < ~/testkey.pub
...which runs the /usr/bin/pbcopy executable, and feeds it input from the file /Users/myName/testkey.pub.

Setting environment variable to shell executed from perl script

I am running a perl file a.pm which invokes b.sh via system command.
Here, b.sh is using find utility whose path is /usr/local/bin.
If I run env on shell directly on machine, I get output as below for PATH variable.
PATH=/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/home/bin:/home/bin/samba::/home/venv/bin/:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin`
Thats why if I run the b.sh directly from shell, it is able to execute find utility.
Now, If I run b.sh via a.pm as mentioned earlier using system(), and when I print PATH env variable in b.sh, its coming as
/bin:/usr/bin:/usr/X11R6/bin:/home/bin:/home/perl5/bin
which does not have /usr/local/bin, and thats why find command is failing.
If I tried to print all ENV variables in perl before invoking system(b.sh), PATH variable is not printed.
Now, I tried adding path variable in a.pm file as follows just before invoking system(b.sh).
$ENV{'PATH'} = '/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin:/home/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/';
Now, if I try to print all ENV variables in perl before invoking system(b.sh), PATH variable is printed with above value.
Still executing the a.pm file, the PATH variable printed in b.sh is same:
/bin:/usr/bin:/usr/X11R6/bin:/home/bin:/home/perl5/bin
How can I add corresponding path /usr/local/bin to shell of b.sh invoked using a.pm?
I suspect that the Perl program is either modifying the path it gets from the shell that invokes it, or that you have left out a step somewhere. For example, if you invoke the Perl program from a different environment, it will likely have a different PATH.
You seemed to have found your answer though. Add the necessary directory to the PATH in the Perl program. But, you say this doesn't work. Again, I think there's some step that you haven't included. I suspect that the way in which you run system overwrites the PATH inherited from the parent.
For example, here's a small Perl program the merely runs a shell script:
#!perl
use v5.10;
$ENV{PATH} = '/bin:/usr/bin';
say "PATH in Perl is $ENV{PATH}";
system( "sh ./pather.sh" );
The shell script echos the PATH:
#!/bin/sh
echo "PATH in shell:" $PATH
When I run this, both PATHs match:
PATH in Perl is /bin:/usr/bin
PATH in shell: /bin:/usr/bin
But, maybe the command in system is something else. The -l switch treats the shell as a login shell, so it will load the various profiles and whatnot:
system( "sh -l ./pather.sh" );
Now the PATH is different in the shell script because my particular profiles overwrote PATH:
PATH in Perl is /bin:/usr/bin
Path in shell: /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin:/usr/local/go/bin:...
Our answers can be more targeted you can produce a minimal working example where we see actual code that demonstrates the problem. Since we don't see what you actually run in system, we can only guess.

What is start faster by ignoring the start-up file?

What is different between /bin/tcsh and /bin/tcsh -f ?
I create environment variables before I run a script. How does 'f' effect ?
The documentation for tcsh has the answer you are looking for:
When a command to be executed is found not to be a builtin command the
shell attempts to execute the command via execve(2). Each word in the
variable path names a directory in which the shell will look for the
command. If the shell is not given a -f option, the shell hashes the
names in these directories into an internal table so that it will try
an execve(2) in only a directory where there is a possibility that the
command resides there. This greatly speeds command location when a
large number of directories are present in the search path. This
hashing mechanism is not used: ... 2. If the shell was given a -f argument.

Cannot properly execute bash script because of a redirection in an environment where root is the owner

My script is executable and I run it as sudo. I tried many workarounds and alternatives to the ">>" operator but nothing seemed to work properly.
My script:
#! /bin/bash
if [[ -z "$1" || -z "$2" ]]; then
exit 1
else
root=$1
fileExtension=$2
fi
$(sudo find $root -regex ".*\.${fileExtension}") >> /home/mux/Desktop/AllFilesOf${fileExtension}.txt
I tried tee, sed and dd of, I also tried running it with bash -c or in sudo -i , nothing worked. Either i get an empty file or a Permission denied error.
I searched thoroughly and read many command manuals but I can't get it to work
The $() operator performs command substitution. When the overall command line is expanded, the command within the parentheses is executed, and the whole construct is replaced with the command's output. After all expansions are performed, the resulting line is executed as a command.
Consider, then, this simplified version of your command:
$(find /etc -regex ".*\.conf") >> /home/mux/Desktop/AllFilesOfconf.txt
On my system that will expand to a ginormous command of the form
/etc/rsyslog.conf /etc/pnm2ppa.conf ... /etc/updatedb.conf >> /home/mux/Desktop/AllFilesOfconf.txt
Note at this point that the redirection is separate from, and therefore independent of, the command in the command substitution. Expanding the command substitution therefore does not cause anything to be written to the target file.
But we're not done! That was just the expansion. Bash now tries to execute the result as a command. In particular, in the above example it tries to execute /etc/rsyslog.conf as a command, with all the other file names as arguments, and with output redirected as specified. But /etc/rsyslog.conf is not executable, so that will fail, producing a "permission denied" message. I'm sure you can extrapolate from there what effects different expansions would produce.
I don't think you mean to perform a command substitution at all, but rather just to run the command and redirect its output to the given file. That would simply be this:
sudo find $root -regex ".*\.${fileExtension}" >> /home/mux/Desktop/AllFilesOf${fileExtension}.txt
Update:
As #CharlesDuffy observed, the redirection in that case is performed with the permissions of the user / process running the script, just as it is in your original example. I have supposed that that is intentional and correct -- i.e. that the script is being run by user 'mux' or by another user that has access to mux's Desktop directory and to any existing file in it that the script might try to create or update. If that is not the case, and you need the redirection, too, to be privileged, then you can achieve it like so:
sudo -s <<END
find $root -regex ".*\.${fileExtension}" >> /home/mux/Desktop/AllFilesOf${fileExtension}.txt
END
That runs an interactive shell via sudo, with its input is redirected from the heredoc. The variable expansions are performed in the host shell from which sudo is executed. In this case the redirection is performed with the identity obtained via sudo, which affects access control, as well as ownership of the file if a new one is created. You could add a chown command if you don't want the output files to be owned by root.

AppleScript : error "sh: lame: command not found" number 127

I am trying to create an AppleScript with commands below. An issue I am having is there is an error at the third line. I have no problem using the lame command in the terminal directly. In addition, lame is not a native Mac utility; I installed it on my own. Does anybody have a solution?
do shell script "cd ~/Downloads"
do shell script "say -f ~/Downloads/RE.txt -o ~/Downloads/recording.aiff"
do shell script "lame -m m ~/Downloads/recording.aiff ~/Downloads/recording.mp3"
-- error "sh: lame: command not found" number 127
do shell script "rm recording.aiff RE.txt"
To complement Paul R's helpful answer:
The thing to note is that do shell script - regrettably - does NOT see the same $PATH as shells created by Terminal.app - a notable absence is /usr/local/bin.
On my OS X 10.9.3 system, running do shell script "echo $PATH" yields merely:
/usr/bin:/bin:/usr/sbin:/sbin
There are various ways around this:
Use the full path to executables, as in Paul's solution.
Manually prepend/append /usr/local/bin, where many non-system executables live, to the $PATH - worth considering if you invoke multiple executables in a single do shell script command; e.g.:
do shell script "export PATH=\"/usr/local/bin:$PATH\"
cd ~/Downloads
say -f ~/Downloads/RE.txt -o ~/Downloads/recording.aiff
lame -m m ~/Downloads/recording.aiff ~/Downloads/recording.mp3
rm recording.aiff RE.txt"
Note how the above use a single do shell script command with multiple commands in a single string - commands can be separated by newlines or, if on the same line, with ;.
This is more efficient than multiple invocations, though adding error handling both inside the script code and around the do shell script command is advisable.
To get the same $PATH that interactive shells see (except additions made in your bash profile), you can invoke eval $(/usr/libexec/path_helper -s); as the first statement in your command string.
Other important considerations with do shell script:
bash is invoked as sh, which results in changes in behavior, most notably:
process substitution (<(...)) is not available
echo by default accepts no options and interprets escape sequences such as \n.
other, subtle changes in behavior; see http://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html
You could address these issues manually by prepending shopt -uo posix; shopt -u xpg_echo; to your command string.
The locale is set to the generic "C" locale instead of to your system's; to fix that, manually prepend export LANG='" & user locale of (system info) & ".UTF-8' to your command string.
No startup files (profiles) are read; this is not surprising, because the shell created is a noninteractive (non-login) shell, but sometimes it's handy to load one's profile by manually by prepending . ~/.bash_profile to the command string; note, however, that this makes your AppleScript less portable.
do shell script command reference: http://developer.apple.com/library/mac/#technotes/tn2065/_index.html
Probably a PATH problem - use the full path for lame, e.g.
do shell script "/usr/local/bin/lame -m m ~/Downloads/recording.aiff ~/Downloads/recording.mp3"
I have been struggling to get the path of an installed BASH command via Applescript for a long time. Using the information here, I finally succeeded.
tell me to set sox_path to (do shell script "eval $(/usr/libexec/path_helper -s); which sox")
Thanks.
Url:http://sourceforge.net/project/showfiles.php?group_id=290&package_id=309
./configure
make install

Resources