Why don't commands work from xargs that work from bash? - xargs

The -t option to xargs makes it display the command it is about to run. The command fails when xargs runs it, but when I copy and paste it to the prompt it works fine.
# echo alpine/3.10 alpine-3-10 | xargs -ti /var/lib/snapd/snap/bin/lxc launch images:{}
/var/lib/snapd/snap/bin/lxc launch images:alpine/3.10 alpine-3-10
Creating the instance
Error: Failed instance creation: The requested image couldn't be found
# /var/lib/snapd/snap/bin/lxc launch images:alpine/3.10 alpine-3-10
Creating alpine-3-10
<works correctly>

You have a list of images that are separated by spaces. You wish to run each of them through a lxc launch.
echo alpine/3.10 alpine-3-10 | tr ' ' '\n' | \
xargs -ti /var/lib/snapd/snap/bin/lxc launch images:{}
This takes your list of image names separated by spaces. The tr command changes spaces in those names to '\n' (newlines). Then the lines are passed to xargs. The default this way is to run only one line per execution.
I test this by using echo /var/lib/snapd/snap/bin/lxc and here are the results:
echo /var/lib/snapd/snap/bin/lxc launch images:alpine/3.10
/var/lib/snapd/snap/bin/lxc launch images:alpine/3.10
echo /var/lib/snapd/snap/bin/lxc launch images:alpine-3-10
/var/lib/snapd/snap/bin/lxc launch images:alpine-3-10

Related

Bash shell script command executes out of order when run through Bitrise

In the bitrise workflow's script step, I added following snippet:
adb shell ps | grep screenrecord | awk ‘{print $2}’ | xargs adb shell kill
Purpose is to kill the process called screenrecord that was started in a previous step and it works fine when I test it on my system. But when this workflow is triggered through bitrise, it fails with following logs:
What is the cause of this issue and how to fix it?
Most likely this is because awk is not outputting the process id. One possible workaround to try is the following:
adb shell ps | grep screenrecord | sed -E 's/[ ]+/ /g' | cut -d' ' -f2 | xargs adb shell kill
where the awk command has been substituted with sed (to remove the multiple spaces) and a cut one (to get the process id).

Making a Bash script that can open multiple terminals and run wget in each

I have to download bulks of over 100,000 docs from a databank using this script:
#!/usr/bin/bash
IFS=$'\n'
set -f
for line in $(cat < "$1")
do
wget https://www.uniprot.org/uniprot/${line}.txt
done
The first time it took over a week to download all the files (all under 8Kb) so I tried opening multiple terminals and running a split of the total.txt (10 equal splits of 10000 files in 10 terminals) and in just 14 hours I had all the documents downloaded, is there a way to make a script do that for me?
this is a sample of what the list looks like:
D7E6X7
A0A1L9C3F2
A3K3R8
W0K0I7
gnome-terminal -e command
or
xterm -e command
or
konsole -e command
Or
terminal -e command
There is an another alternative to make it fast.
Right now your downloads are synchronized i.e next download process is not started until current one is finished.
Search for how to make command asynchronous/run in background on unix.
When you were doing this by hand, opening multiple terminals made sense. If you want to script this, you can run multiple processes from one terminal/script. You could use xargs to start multiple processes simultaneously:
xargs -a list.txt -n 1 -P 8 -I # bash -c "wget https://www.uniprot.org/uniprot/#.txt"
Where:
-a list.txt tells xargs to use the list.txt file as input.
-n 1 tells xargs to use a maximum of one argument (from the input) for each command it runs.
-P 8 tells xargs to run 8 commands at a time, you can change this to suit your system/requirements.
-I # tells xargs to use "#" to represent the input (i.e. the line from your file).

How do I get the PID of a command nested within the quotes?

I am trying to get the PID of the command within the quotes (e.g. some-command-here) whilst being able to interact with the process spawned by some-command-here:
x-terminal-emulator -e "some-command-here" &> /dev/null
For example, sometimes apt full-upgrade -y can require user input, thus it is important that the process spawned by some-command-here remain interactive.
x-terminal-emulator -e "some-command-here & echo $! >/tmp/pid" &> /dev/null
cat /tmp/pid
... or get rid of the &>/dev/null:
x-terminal-emulator -e "some-command-here & echo $!"
So, with a bit more testing and research, it seems that this task can be accomplished utilizing ps ax, grep, xargs & cut.
ps ax | grep -v "grep" | grep "sh -c" | grep "some-command-here" | xargs | cut -d ' ' -f 1
🤔How does this work?
When x-terminal-emulator is passed -e it spawns a new shell window and passes it the command within the quotes. In order to execute the command, it passes the new shell the command sh -c along with the quoted command. Thus, sh -c some-command-here. Which is utilized within the searching of the PID above.
ps ax lists the currently running processes.
grep -v "grep" searches the output and removes any processes that contain grep as a process simply because when we launch this query, a process under grep will be created.
grep "sh -c" searches the output for a process that contains sh -c.
grep "some-command-here" searches the output of ps ax for a process that matches what is within the quotes.
xargs converts the output of grep "sh -c some-command-here" into a space delimited list.
cut -d ' ' -f 1 removes the spaces and grabs the first result. Which returns the PID of the process in question.

How to filter docker client environment variables into a docker run command?

Suppose on my docker client machine I have the following environment variables:
myValA=B
DOCKER_CONTAINER_VALUE_C=networksettingD
myValE=F
DOCKER_CONTAINER_VALUE_G=arbitrarySettingH
and I want to pass two of these values into my Docker container I'm running. (The ones containing DOCKER_CONTAINER).
Now I could manually hardcode it, like this:
docker run -e DOCKER_CONTAINER_VALUE_C='networksettingD' -e DOCKER_CONTAINER_VALUE_G='arbitrarySettingH' --name container_name dockerhub_id/image_name
But I want to automate this process.
Something like:
docker run -e ${env | grep "DOCKER_CONTAINER"} ...
My question is: How to filter docker client environment variables into a docker run command?
You could do something like this:
set | grep DOCKER_CONTAINER > env_file
docker run --env-file env_file ...
Or if you really want a single command line:
docker run --env-file <(set | grep DOCKER_CONTAINER) ...
The <(...) construct is bash syntax for process substitution. From
bash(1):
Process substitution is supported on systems that support named pipes (FIFOs) or the
/dev/fd method of naming open files. It takes the form of <(list) or >(list). The
process list is run with its input or output connected to a FIFO or some file in
/dev/fd. The name of this file is passed as an argument to the current command as the
result of the expansion.
Something simple like:
docker run -e $(set | echo $(sed -n "/^DOC.*_CON.*_VAL.*/s/^/-e /p")" ")--name container_name dockerhub_id/image_name
$( ) -- run command
set -- list environment variables
sed -n -- do no print
match string ^DOC._CON._VAL.*
substitute "-e " for the beginning of line character
p -- print matches
" " -- add space between results
You can include the full match string; I usually just go for the shortest...
Verified this works.
env | { sed -n '/DOCKER/s/^/-e /p' ; echo myimage; } | xargs docker run

BASH Command save to variable with a variable in the command

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.

Resources