I have a command I want to run first I ran another command to get a directory which is saved in a variable:
path_white="/sys/block/sdb"
Then I want to run another command using this variable and store the output in a variable. I get errors and don't know what I am doing wrong. Any help will be appreciated.
path_pci_white=$(ll $path_white | xargs | cut -d / -f 8 | cut -b 6-13)
it seems that it is not running the entire command below is the error
/sys/block/sdb : is a directory
when i run
ll /sys/block/sdb | xargs | cut -d / -f 8 | cut -b 6-13
in the terminal i get what i want output I just want to use a variable and put the output into a variable
Thanks
ll is an alias for ls -l, and aliases aren't defined in shell scripts. Use an explicit ls -l instead.
There should not be a pipe after xargs. xargs takes as arguments the command it will run. Otherwise there is no point to it.
Related
I have the below code to find out the number of instances of current script running that is running with same arg1. But looks like the script creates a subshell and executes this command which also shows up in output. What would be the better approach to find the number of instances of running script ?
$cat test.sh
#!/bin/bash
num_inst=`ps -ef | grep $0 | grep $1 | wc -l`
echo $num_inst
$ps aux | grep test.sh | grep arg1 | grep -v grep | wc -l
0
$./test.sh arg1 arg2
3
$
I am looking for a solution that matches all running instance of ./test.sh arg1 arg2 not the one with ./test.sh arg10 arg20
The reason this creates a subshell is that there's a pipeline inside the command substitution. If you run ps -ef alone in a command substitution, and then separately process the output from that, you can avoid this problem:
#!/bin/bash
all_processes=$(ps -ef)
num_inst=$(echo "$all_processes" | grep "$0" | grep -c "$1")
echo "$num_inst"
I also did a bit of cleanup on the script: double-quote all variable references to avoid weird parsing, used $() instead of backticks, and replaced grep ... | wc -l with grep -c.
You might also replace the echo "$all_processes" | ... with ... <<<"$all_processes" and maybe the two greps with a single grep -c "$0 $1":
...
num_inst=$(grep -c "$0 $1" <<<"$all_processes")
...
Modify your script like this:
#!/bin/bash
ps -ef | grep $0 | wc -l
No need to store the value in a variable, the result is printed to standard out anyway.
Now why do you get 3?
When you run a command within back ticks (fyi you should use syntax num_inst=$( COMMAND ) and not back ticks), it creates a new sub-shell to run COMMAND, then assigns the stdout text to the variable. So if you remove the use of $(), you will get your expected value of 2.
To convince yourself of that, remove the | wc -l, you will see that num_inst has 3 processes, not 2. The third one exists only for the execution of COMMAND.
When I run the following code in a bash script I receive an output of 2
#!/bin/bash
HIPPO=$(ps -a | grep hippo | wc -l)
echo "$HIPPO"
However when I run the command ps -a | grep hippo | wc -l straight from a command prompt I get an output of 0
Reading the documentation on ps particularly the -a flag, I'm not understanding why the output is different.
How is called your script? If you named it with hippo, it will count in your ps call.
https://superuser.com/questions/935374/difference-between-and-in-shell-script
When you do the command substitution, the command gets runs once according to the above. So I am assuming, the echo is picking a zombie process that ran that command.
working a script that lists or outputs specific files on a windows machine directory when executed a script from a Linux server
Here is the current script we got, it lists all contents in the windows directory but my requirement is to filter out the required ones
echo "ls -l ${TARGET_ICT_DIR}\nquit\n" | sftp ${SFTP_LOGIN} | tee /tmp/ver_ict_rel_dest_${L_CURR_PID}.txt
The above command outputs all files in that windows directory but im looking for files that only searches below files:
anchor.jar
rename.txt
zipper.dat
Please suggest
Will this insertion of grep in the pipeline do the trick?
echo "ls -l ${TARGET_ICT_DIR}\nquit\n" |
sftp ${SFTP_LOGIN} |
grep -E ' (anchor\.jar|rename\.txt|zipper.dat)\r?$' |
tee /tmp/ver_ict_rel_dest_${L_CURR_PID}.txt
Do not know if the check for \r is necessary -- but... Windows... Also, in comment #ghoti noted that \r might not translate well to all versions of grep and shell. You could try something like the following if you run into such:
echo "ls -l ${TARGET_ICT_DIR}\nquit\n" |
sftp ${SFTP_LOGIN} |
grep -E " (anchor\.jar|rename\.txt|zipper.dat)$(printf '\r')?$" |
tee /tmp/ver_ict_rel_dest_${L_CURR_PID}.txt
(Both variants of the ls -l | grep -E ... part was tested with dash and bash on Linux.)
i used below one and it satisfied my condition
echo "ls -l {anchor.jar,rename.txt,zipper.dat} ${TARGET_ICT_DIR}\nquit\n" | sftp ${SFTP_LOGIN} | tee /tmp/ver_ict_rel_dest_${L_CURR_PID}.txt
I'm trying to do the following with xargs
pacman -Q | grep xf86-video | awk '{print $1}' | xargs pacman -R to remove all xf86-video-* driver on my machine. To make the question more clear, here is the output of pacman -Q | grep xf86-video | awk '{print $1}':
xf86-video-ark
xf86-video-ati
xf86-video-dummy
xf86-video-fbdev
xf86-video-glint
xf86-video-i128
xf86-video-intel
xf86-video-mach64
xf86-video-neomagic
xf86-video-nouveau
....
when I redirect the result to xargs, the output looks like this:
The point is, the command which xargs is about to execute need user to do some additional input(as you can see it needs a Yes/No), but xargs automatically add a unknown symbol #, and exit, which causes my purpose UNACHIEVED.
WHY xargs would do this or, what can I do to use xargs for command with prompt?
You can use
xargs -a <(pacman -Q | awk '/xf86-video/{print $1}') pacman -R
Explanation:
Without further arguments xargs does not work with interactive (command line) applications.
The reason for that is, that by defaultxargs gets its input from stdin but interactive applications also expect input from stdin. To prevent the applications from grabbing input that is intended for xargs, xargs redirects stdin from /dev/null for the applications it runs. This leads to the application just receiving an EOF. (Running just pacman -R SOMEPACKAGE and pressing Ctrl+D has the same effect).
To get xargs to work with interactive commands you have to use the --arg-file=FILE argument (short -a FILE). This tells xargs to get the arguments from FILE. This also leaves stdin unchanged.
So you could either put your package list into a temporary file
pacman -Q | awk '/xf86-video/{print $1}' > /tmp/packagelist
xargs -a /tmp/packagelist pacman -R
rm /tmp/packagelist
or you can use zsh's process substitution mechanism <(list). When executing a line with <(list), <(list) is replaced by a filename from where the output of list can be read.
xargs -a <(pacman -Q | awk '/xf86-video/{print $1}') pacman -R
The single # you get is not from xargs but from zsh itself. If the shell options PROMPT_CR and PROMPT_SP are set (which both are by default) zsh tries to preserve partial lines, that is lines that did not end with a newline. To signify that such a line has been preserved zsh prints an inverse+bold character at the end of that line, by default % for normal users and # for root.
You can eliminate the use of xargs with a single hyphen
Additionally, if stdin is not from a terminal and a single hyphen (-) is passed as an argument, targets will be read from stdin.
— https://archlinux.org/pacman/pacman.8.html
pacman -Q | awk '/xf86-video/{print $1}' | pacman -R -
You can use xargs, though ...
If you wish to use xargs, use it's -o, --open-tty option:
--open-tty
-o
Reopen stdin as /dev/tty in the child process before executing the command, thus allowing that command to be associated to the terminal while xargs reads from a different stream, e.g. from a pipe. This is useful if you want xargs to run an interactive application.
grep -lz PATTERN * | xargs -0o vi ①
— https://www.gnu.org/software/findutils/manual/html_node/find_html/xargs-options.html
① That should be an uppercase Z grep option (bug filed).
For your particular case:
pacman -Q | awk '/xf86-video/{print $1}' | xargs -o pacman -R
You need to run pacman the second time with the --noconfirm option:
pacman -Q | grep xf86-video | awk '{print $1}' | xargs pacman -R --noconfirm
This will disable 'are you sure' messages, and do things without requiring input.
I have a Makefle with the following rule
bash -c "find . |grep -E '\.c$|\.h$|\.cpp$|\.hpp$|Makefile' | xargs cat | wc -l"
I'm expecting make to run the quoted bash script and to return the number of line in my project.
Running directly the command in a terminal does the work, but it doesn't work in makefile.
If I remove $ from the script, it does work ... but not as expected (since I only want *.{c,cpp,h,hpp,Makefile}.
Why bash -c doesn't run correctly my script?
if you write the rule like the following, it should produce the result you want:
target:
#echo $(shell find . | grep -E '\.c$$|\.h$$|\.cpp$$|\.hpp$$|Makefile' | xargs cat | wc -l)
In Makefiles, $ is used for make variables such as $(HEADERS), where HEADERS would have been defined previously using =.
To use a $ in inline bash, you have to double them to escape them. $$VAR will refer to a shell variable, and .c$$ and so on should escape the $ for the regex you're working with.
The following should suffice in escaping the $'s for what you're trying to accomplish
bash -c "find . |grep -E '\.c$$|\.h$$|\.cpp$$|\.hpp$$|Makefile' | xargs cat | wc -l"
Additionally, you can use bash globally in your Makefile as opposed to the default /bin/sh if you add this declaration:
SHELL = /bin/bash
With the above, you should be able to use the find command without needing the bash -c and quotes. The following should work if SHELL is defined as above:
find . |grep -E '\.c$$|\.h$$|\.cpp$$|\.hpp$$|Makefile' | xargs cat | wc -l
Also, note that you can, and will often see SubShells used for this purpose. These are created with (). This will make any variables defined by the inner shell local to that shell and its group of commands.