Passing static variables to GNU Parallel [closed] - linux

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
In a bash script I am trying to pass multiple distinct fastq files and several user-provided static variables to GNU Parallel. I can't hardcode the static variables because while they do not change within the script, they are set by the user and are variable between uses. I have tried a few different ways but get an error argument -b/--bin: expected one argument
Attempt 1:
binSize="10000"
outputDir="output"
errors="1"
minReads="10"
ls fastq_F* | parallel "python myscript.py -f split_fastq_F{} -b $binSize -o $outputDir -e $errors -p -t $minReads"
Attempt 2:
my_func() {
python InDevOptimizations/DemultiplexUsingBarcodes_New_V1.py \
-f split_fastq_F$1 \
-b $binSize \
-o $outputDir \
-e $errors \
-p \
-t $minReads
}
export -f my_func
ls fastq_F* | parallel my_func
It seems clear that I am not correctly passing the static variables... but I can't seem to grasp what the correct way to do this is.

Always try --dr when GNU Parallel does not do what you expect.
binSize="10000"
outputDir="output"
errors="1"
minReads="10"
ls fastq_F* | parallel --dr "python myscript.py -f split_fastq_F{} -b $binSize -o $outputDir -e $errors -p -t $minReads"
You are using " and not ' so the variables should be substituted by the shell before GNU Parallel starts.
If the commands are run locally (i.e. not remote) you can use export VARIABLE.
If run on remote servers, use env_parallel:
env_parallel --session
alias myecho='echo aliases'
env_parallel -S server myecho ::: work
myfunc() { echo functions $*; }
env_parallel -S server myfunc ::: work
myvar=variables
env_parallel -S server echo '$myvar' ::: work
myarray=(arrays work, too)
env_parallel -k -S server echo '${myarray[{}]}' ::: 0 1 2
env_parallel --end-session

Related

Automated script install using bash [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 3 years ago.
Improve this question
I'm trying to script install the below, how can I answer "y" at the prompt within the command
wget -O - mic.raspiaudio.com | sudo bash
I have tried the usual but this wont work
echo "y" | wget -O - mic.raspiaudio.com | sudo bash
Disclaimer: The solution below works for script that have a non-interactive switch.
I believe the echo won't work on this because it's not writing to the /dev/tty that the bash spawned. You can do it using the default feature bash provides.
From the man page:
-c If the -c option is present, then commands are read from the first
non-option argument command_string. If there are arguments after the
command_string, the first argument is assigned to $0 and any remaining
arguments are assigned to the positional parameters.
If you use -c option with bash, you can supply args to script that will run and those will be placed as mentioned in the man page. eg:
bash -c "script" "arg0" "arg1" .... The arg0 will be placed in $0 and arg1 will be placed in $1 and so on.
Now, I don't know if this can be generalized, but this solution will only work if there is a non-interactive mode in the script.
If you see the script it has the following function:
FORCE=$1
confirm() {
if [ "$FORCE" == '-y' ]; then
true
else
read -r -p "$1 [y/N] " response < /dev/tty
if [[ $response =~ ^(yes|y|Y)$ ]]; then
true
else
false
fi
fi
}
And is used as :
if confirm "Do you wish to continue"
then
echo "You are good to go"
fi
So, if we can set the $1 to "-y" it won't ask for a confirmation, We will try to do that same by:
$ bash -c "$( wget -qO - mic.raspiaudio.com)" "dummy" "-y"
This should work for the script, provided it does not have any other interactive options. I have not tested the original script by my own minimal script and it seems to work. eg:
$ bash -c "$(wget -qO - localhost:8080/test.sh)" "dummy" -y
You are good to go
$ bash -c "$(wget -qO - localhost:8080/test.sh)"
Do you wish to continue [y/N] y
You are good to go

GNU parallel inheriting environment variable while executing a local script

Suppose I have foo.sh that calls bar.sh using parallel:
# foo.sh
#! /bin/bash
parallel -N 3 bar.sh ::: $(seq 10)
My bar.sh works like this: if there is an environment variable (e.g. DEBUG=1) set, then it will output lots of debug info.
Ideally I want to simply execute my foo.sh like such:
$ DEBUG=1 foo.sh
Normally, foo.sh has $DEBUG value, as well as bar.sh sees it. But now with me using GNU parallel to call bar.sh, which is a local program, my bar.sh no longer has the DEBUG value set.
I read that --env only works if I had remote execution -S set, and from me trying it does not seem to work for me.
Is there a way to get my parallel'ed bar.sh to simply "inherit" the environment settings of my foo.sh? I really don't want to spell out each and every environment variable and their values when calling bar.sh in parallel.
TIA
You are looking for env_parallel which does exactly this.
Put this in $HOME/.bashrc:
. `which env_parallel.bash`
E.g. by doing:
echo '. `which env_parallel.bash`' >> $HOME/.bashrc
aliases
alias myecho='echo aliases'
env_parallel myecho ::: work
env_parallel -S server myecho ::: work
env_parallel --env myecho myecho ::: work
env_parallel --env myecho -S server myecho ::: work
functions
myfunc() { echo functions $*; }
env_parallel myfunc ::: work
env_parallel -S server myfunc ::: work
env_parallel --env myfunc myfunc ::: work
env_parallel --env myfunc -S server myfunc ::: work
variables
myvar=variables
env_parallel echo '$myvar' ::: work
env_parallel -S server echo '$myvar' ::: work
env_parallel --env myvar echo '$myvar' ::: work
env_parallel --env myvar -S server echo '$myvar' ::: work
arrays
myarray=(arrays work, too)
env_parallel -k echo '${myarray[{}]}' ::: 0 1 2
env_parallel -k -S server echo '${myarray[{}]}' ::: 0 1 2
env_parallel -k --env myarray echo '${myarray[{}]}' ::: 0 1 2
env_parallel -k --env myarray -S server echo '${myarray[{}]}' ::: 0 1 2
env_parallel is part of GNU Parallel 20160722. It is beta quality, so please report bugs if you find any.
If your know your UNIX you will know that you cannot use aliases, non-exported functions, non-exported variables, and non-exported arrays in shells started from the current shell (e.g. in bash -c); and especially not if the shell is remote (e.g. ssh server myalias). With env_parallel this common knowledge has to be revised into: you cannot do it without cheating.
In order to copy the entire environment, use _ as the variable exported by --env:
parallel --env _ -N 3 bar.sh ::: $(seq 10)

Execute a find command with expression from a shell script [duplicate]

This question already has answers here:
Why does shell ignore quoting characters in arguments passed to it through variables? [duplicate]
(3 answers)
Closed 6 years ago.
I'm trying to write a database call from within a bash script and I'm having problems with a sub-shell stripping my quotes away.
This is the bones of what I am doing.
#---------------------------------------------
#! /bin/bash
export COMMAND='psql ${DB_NAME} -F , -t --no-align -c "${SQL}" -o ${EXPORT_FILE} 2>&1'
PSQL_RETURN=`${COMMAND}`
#---------------------------------------------
If I use an 'echo' to print out the ${COMMAND} variable the output looks fine:
echo ${COMMAND}
screen output:-
#---------------
psql drupal7 -F , -t --no-align -c "SELECT DISTINCT hostname FROM accesslog;" -o /DRUPAL/INTERFACES/EXPORTS/ip_list.dat 2>&1
#---------------
Also if I cut and paste this screen output it executes just fine.
However, when I try to execute the command as a variable within a sub-shell call, it gives an error message.
The error is from the psql client to the effect that the quotes have been removed from around the ${SQL} string.
The error suggests psql is trying to interpret the terms in the sql string as parameters.
So it seems the string and quotes are composed correctly but the quotes around the ${SQL} variable/string are being interpreted by the sub-shell during the execution call from the main script.
I've tried to escape them using various methods: \", \\", \\\", "", \"" '"', \'"\', ... ...
As you can see from my 'try it all' approach I am no expert and it's driving me mad.
Any help would be greatly appreciated.
Charlie101
Instead of storing command in a string var better to use BASH array here:
cmd=(psql ${DB_NAME} -F , -t --no-align -c "${SQL}" -o "${EXPORT_FILE}")
PSQL_RETURN=$( "${cmd[#]}" 2>&1 )
Rather than evaluating the contents of a string, why not use a function?
call_psql() {
# optional, if variables are already defined in global scope
DB_NAME="$1"
SQL="$2"
EXPORT_FILE="$3"
psql "$DB_NAME" -F , -t --no-align -c "$SQL" -o "$EXPORT_FILE" 2>&1
}
then you can just call your function like:
PSQL_RETURN=$(call_psql "$DB_NAME" "$SQL" "$EXPORT_FILE")
It's entirely up to you how elaborate you make the function. You might like to check for the correct number of arguments (using something like (( $# == 3 ))) before calling the psql command.
Alternatively, perhaps you'd prefer just to make it as short as possible:
call_psql() { psql "$1" -F , -t --no-align -c "$2" -o "$3" 2>&1; }
In order to capture the command that is being executed for debugging purposes, you can use set -x in your script. This will the contents of the function including the expanded variables when the function (or any other command) is called. You can switch this behaviour off using set +x, or if you want it on for the whole duration of the script you can change the shebang to #!/bin/bash -x. This saves you explicitly echoing throughout your script to find out what commands are being run; you can just turn on set -x for a section.
A very simple example script using the shebang method:
#!/bin/bash -x
ec() {
echo "$1"
}
var=$(ec 2)
Running this script, either directly after making it executable or calling it with bash -x, gives:
++ ec 2
++ echo 2
+ var=2
Removing the -x from the shebang or the invocation results in the script running silently.

.bash_profile ldapsearch function not outputting to terminal [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 8 years ago.
I have a bash function in my .bash_profile that is not returning results to the terminal.
When I run the command as normal via the CLI results are returned.
ldap_check_cleaup ()
{
ldapsearch -LLL -h itdsvbms.SomeDomain.org -p 389 \
-D "uid=SomeUser,o=SomeDomain.org" -w SomePassWord -b "ou=People,o=SomeDomain.org" \
-s sub '(&(ReservedRMAliases=$1)(!(RMid=*))(RMAliasUpdateDate=12/01/2012 19:02:00)(RMAliasStatus=IN)(status=IN))' | \
tee /dev/tty
}
running ldap_check_clenaup TestRecord returns no output when executed from the bash prompt. TestRecord does exist and when the following command is run from the CLI, the correct record is returned:
ldapsearch -LLL -h itdsvbms.SomeDomain.org -p 389 -D "uid=SomeUser,o=SomeDomain.org" \
-w SomePassWord -b "ou=People,o=SomeDomain.org" \
-s sub '(&(ReservedRMAliases=TestRecord)(!(RMid=***))(RMAliasUpdateDate=12/01/2012 19:02:00)(RMAliasStatus=IN)(status=IN))' | \
tee /dev/tty`
The lack of out put only happens when I try to use this ldapsearch and the arguments as a bash function.
I think this may be related to using ' instead of " for the attribute (!(RMid=*)) but I am unsure, please help.
You need to use double-quotes around the argument that contains $1. Variable interpolation is not performed inside single-quoted strings.

How can I show the wget progress bar only? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
For example:
wget http://somesite.com/TheFile.jpeg
downloading: TheFile.tar.gz ...
--09:30:42-- http://somesite.com/TheFile.jpeg
=> `/home/me/Downloads/TheFile.jpeg'
Resolving somesite.co... xxx.xxx.xxx.xxx.
Connecting to somesite.co|xxx.xxx.xxx.xxx|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1,614,820 (1.5M) [image/jpeg]
25% [======> ] 614,424 173.62K/s ETA 00:14
How can I get it to look like the following?
downloading: TheFile.jpeg ...
25% [======> ] 614,424 173.62K/s ETA 00:14
I know curl can do that. However, I need to get wget to do that job.
Use:
wget http://somesite.com/TheFile.jpeg -q --show-progress
-q: Turn off wget's output
--show-progress: Force wget to display the progress bar no matter what its verbosity level is set to
You can use the following filter:
progressfilt ()
{
local flag=false c count cr=$'\r' nl=$'\n'
while IFS='' read -d '' -rn 1 c
do
if $flag
then
printf '%s' "$c"
else
if [[ $c != $cr && $c != $nl ]]
then
count=0
else
((count++))
if ((count > 1))
then
flag=true
fi
fi
fi
done
}
Usage:
$ wget --progress=bar:force http://somesite.com/TheFile.jpeg 2>&1 | progressfilt
100%[======================================>] 15,790 48.8K/s in 0.3s
2011-01-13 22:09:59 (48.8 KB/s) - 'TheFile.jpeg' saved [15790/15790]
This function depends on a sequence of 0x0d0x0a0x0d0x0a0x0d being sent right before the progress bar is started. This behavior may be implementation dependent.
Run using these flags:
wget -q --show-progress --progress=bar:force 2>&1
You can use the follow option of tail:
wget somesite.com/TheFile.jpeg --progress=bar:force 2>&1 | tail -f -n +6
The +6 is to delete the first 6 lines. It may be different on your version of wget or your language.
You need to use --progress=bar:force otherwise wget switches to the dot type.
The downside is that the refreshing is less frequent than with wget (looks like every 2 seconds). The --sleep-interval option of tail seems to be meant just for that, but it didn't change anything for me.
The option --show-progress, as pointed out by others, is the best option, but it is available only since GNU wget 1.16, see Noteworthy changes in wget 1.16.
To be safe, we can first check if --show-progress is supported:
# set progress option accordingly
wget --help | grep -q '\--show-progress' && \
_PROGRESS_OPT="-q --show-progress" || _PROGRESS_OPT=""
wget $_PROGRESS_OPT ...
Maybe it's time to consider just using curl.
You can use standard options:
wget --progress=bar http://somesite.com/TheFile.jpeg
This is another example:
download() {
local url=$1
echo -n " "
wget --progress=dot $url 2>&1 | grep --line-buffered "%" | sed -u -e "s,\.,,g" | awk '{printf("\b\b\b\b%4s", $2)}'
echo -ne "\b\b\b\b"
echo " DONE"
}
Here is a solution that will show you a dot for each file (or line, for that matter). It is particularly useful if you are downloading with --recursive. This won't catch errors and may be slightly off if there are extra lines, but for general progress on a lot of files it is helpful:
wget -r -nv https://example.com/files/ | \
awk -v "ORS=" '{ print "."; fflush(); } END { print "\n" }'
This is not literally an answer but this snippet might also be helpful to some coming here for e.g. "zenity wget GUI":
LANG=C wget -O /dev/null --progress=bar:force:noscroll --limit-rate 5k http://nightly.altlinux.org/sisyphus/ChangeLog 2>&1 | stdbuf -i0 -o0 -e0 tr '>' '\n' | stdbuf -i0 -o0 -e0 sed -rn 's/^.*\<([0-9]+)%\[.*$/\1/p' | zenity --progress --auto-close
What was crucial for me is stdbuf(1).

Resources