Linux, out of memory in bash script, not interactive, not ulimit? - c

What linux settings could result in a C++ program run as:
jellyfish count -m 31 -t 40 -C -s 105 -o k_u_hash_0 pe.cor.fa
working fine when that command is executed in a terminal, but crashing in a bash script? In the latter case it asks for 411428571480 bytes before it exits - immediately. This is odd because when run interactively top shows it with just 10's of Gb of Virt and Res memory many minutes after it started running.
ulimit -a
in both environments shows:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 2067197
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 1024
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
/proc/meminfo shows:
CommitLimit: 615693660 kB
Committed_AS: 48320500 kB
and even stranger, a small C test program, which just calloc's ever larger memory blocks than releases them, when run in either environment, including immediately before jellyfish, did this:
calloc_test
Testing 4294967296
Testing 8589934592
Testing 17179869184
Testing 34359738368
Testing 68719476736
Testing 137438953472
Testing 274877906944
Testing 549755813888
Testing 1099511627776
FAILED
That is, it was able to allocate a 549 Gb block, which is larger than the one jellyfish asked for, and memory allocation behaved the same in both environments.
There is no LD_LIBRARY_PATH set in either case.
Can anybody suggest what might differ in the two environments to account for the difference in the action of a subset of memory allocating programs? (A subset of one at this point.)
Thank you.
As requested, this is the script (only down to the point of failure plus 3 extra lines):
#!/bin/bash
# assemble.sh generated by masurca
CONFIG_PATH="/home/mathog/do_masurca/project.cfg"
CMD_PATH="/home/mathog/MaSuRCA/bin/masurca"
# Test that we support <() redirection
(eval "cat <(echo test) >/dev/null" 2>/dev/null) || {
echo >&2 "ERROR: The shell used is missing important features."
echo >&2 " Run the assembly script directly as './$0'"
exit 1
}
# Parse command line switches
while getopts ":rc" o; do
case "${o}" in
c)
echo "configuration file is '$CONFIG_PATH'"
exit 0
;;
r)
echo "Rerunning configuration"
exec perl "$CMD_PATH" "$CONFIG_PATH"
echo "Failed to rerun configuration"
exit 1
;;
*)
echo "Usage: $0 [-r] [-c]"
exit 1
;;
esac
done
set +e
# Set some paths and prime system to save environment variables
save () {
(echo -n "$1=\""; eval "echo -n \"\$$1\""; echo '"') >> environment.sh
}
GC=
RC=
NC=
if tty -s < /dev/fd/1 2> /dev/null; then
GC='\e[0;32m'
RC='\e[0;31m'
NC='\e[0m'
fi
log () {
d=$(date)
echo -e "${GC}[$d]${NC} $#"
}
fail () {
d=$(date)
echo -e "${RC}[$d]${NC} $#"
exit 1
}
signaled () {
fail Interrupted
}
trap signaled TERM QUIT INT
rm -f environment.sh; touch environment.sh
# To run tasks in parallel
run_bg () {
semaphore -j $NUM_THREADS --id masurca_$$ -- "$#"
}
run_wait () {
semaphore -j $NUM_THREADS --id masurca_$$ --wait
}
export PATH="/home/mathog/MaSuRCA/bin:/home/mathog/MaSuRCA/bin/../CA/Linux-amd64/bin:$PATH"
save PATH
export PERL5LIB=/home/mathog/MaSuRCA/bin/../lib/perl${PERL5LIB:+:$PERL5LIB}
save PERL5LIB
NUM_THREADS=40
save NUM_THREADS
log 'Processing pe library reads'
rm -rf meanAndStdevByPrefix.pe.txt
echo 'pe 400 20' >> meanAndStdevByPrefix.pe.txt
run_bg rename_filter_fastq 'pe' <(exec expand_fastq '/home/mathog/SPUR_datasets/pe_400_R1.fastq' | awk '{if(length($0>200)) print substr($0,1,200); else print $0;}') <(exec expand_fastq '/home/mathog/SPUR_datasets/pe_400_R2.fastq' | awk '{if(length($0>200)) print substr($0,1,200); else print $0;}' ) > 'pe.renamed.fastq'
run_wait
head -q -n 40000 pe.renamed.fastq | grep --text -v '^+' | grep --text -v '^#' > pe_data.tmp
export PE_AVG_READ_LENGTH=`awk '{if(length($1)>31){n+=length($1);m++;}}END{print int(n/m)}' pe_data.tmp`
save PE_AVG_READ_LENGTH
echo "Average PE read length $PE_AVG_READ_LENGTH"
KMER=`for f in pe.renamed.fastq;do head -n 80000 $f |tail -n 40000;done | perl -e 'while($line=<STDIN>){$line=<STDIN>;chomp($line);push(#lines,$line);$line=<STDIN>;$line=<STDIN>}$min_len=100000;$base_count=0;foreach $l(#lines){$base_count+=length($l);push(#lengths,length($l));#f=split("",$l);foreach $base(#f){if(uc($base) eq "G" || uc($base) eq "C"){$gc_count++}}} #lengths =sort {$b <=> $a} #lengths; $min_len=$lengths[int($#lengths*.75)]; $gc_ratio=$gc_count/$base_count;$kmer=0;if($gc_ratio<0.5){$kmer=int($min_len*.7);}elsif($gc_ratio>=0.5 && $gc_ratio<0.6){$kmer=int($min_len*.5);}else{$kmer=int($min_len*.33);} $kmer++ if($kmer%2==0); $kmer=31 if($kmer<31); $kmer=127 if($kmer>127); print $kmer'`
save KMER
echo "choosing kmer size of $KMER for the graph"
KMER_J=$KMER
MIN_Q_CHAR=`cat pe.renamed.fastq |head -n 50000 | awk 'BEGIN{flag=0}{if($0 ~ /^\+/){flag=1}else if(flag==1){print $0;flag=0}}' | perl -ne 'BEGIN{$q0_char="#";}{chomp;#f=split "";foreach $v(#f){if(ord($v)<ord($q0_char)){$q0_char=$v;}}}END{$ans=ord($q0_char);if($ans<64){print "33\n"}else{print "64\n"}}'`
save MIN_Q_CHAR
echo MIN_Q_CHAR: $MIN_Q_CHAR
JF_SIZE=`ls -l *.fastq | awk '{n+=$5}END{s=int(n/50); if(s>80000000000)printf "%.0f",s;else print "80000000000";}'`
save JF_SIZE
perl -e '{if(int('$JF_SIZE')>80000000000){print "WARNING: JF_SIZE set too low, increasing JF_SIZE to at least '$JF_SIZE', this automatic increase may be not enough!\n"}}'
log Creating mer database for Quorum.
quorum_create_database -t 40 -s $JF_SIZE -b 7 -m 24 -q $((MIN_Q_CHAR + 5)) -o quorum_mer_db.jf.tmp pe.renamed.fastq && mv quorum_mer_db.jf.tmp quorum_mer_db.jf
if [ 0 != 0 ]; then
fail Increase JF_SIZE in config file, the recommendation is to set this to genome_size*coverage/2
fi
log Error correct PE.
quorum_error_correct_reads -q $((MIN_Q_CHAR + 40)) --contaminant=/home/mathog/MaSuRCA/bin/../share/adapter.jf -m 1 -s 1 -g 1 -a 3 -t 40 -w 10 -e 3 -M quorum_mer_db.jf pe.renamed.fastq --no-discard -o pe.cor --verbose 1>quorum.err 2>&1 || {
mv pe.cor.fa pe.cor.fa.failed && fail Error correction of PE reads failed. Check pe.cor.log.
}
log Estimating genome size.
jellyfish count -m 31 -t 40 -C -s $JF_SIZE -o k_u_hash_0 pe.cor.fa
export ESTIMATED_GENOME_SIZE=`jellyfish histo -t 40 -h 1 k_u_hash_0 | tail -n 1 |awk '{print $2}'`
save ESTIMATED_GENOME_SIZE
echo "Estimated genome size: $ESTIMATED_GENOME_SIZE"

Here's (some) useless memory and CPU cycle waste in the script:
cat pe.renamed.fastq | head -n 50000 | ...
You should instead avoid the useless use of cat with
head -n 50000 pe.renamed.fastq | ...

Related

Input and output for AWK

I am trying to run this for-loop and just seeking some feedback on what it is supposed to do:
for FF in `cat bams`
do
F=$(basename $FF)
F_PREFIX=${F/.bam/}
angsd -i $F -anc $GENOME_REF $FILTERS -GL 1 -doSaf 1 -doCounts 1 -out ${F_PREFIX} && realSFS ${F_PREFIX}.saf.idx >${F_PREFIX}.ml | awk -v file=$F '{print file\"\t\"(\$1+\$2+\$3)\"\t\"\$2/(\$1+\$2+\$3)}' ${F_PREFIX}.ml >> goodbams.goodsites.het
done
The issue I have is piping the output to awk.
Can someone comment if the input file (file=$F) is the original file under
F/.bam
or
{F_PREFIX}.saf.idx
or
${F_PREFIX}.ml
I am also unclear what the second ${F_PREFIX}.ml is supposed to do in the awk script.
This to me looks like the .saf.idx output should be stored in the ${F_PREFIX}.ml file, and then awk should execute the command using the ${F/.bam/} file and also put the output into ${F_PREFIX}.ml.
Then those total ${F_PREFIX}.ml output should go into goodbams.goodsites.het
Would someone be able to confirm that interpretation?
To get this to work, I had to break it into multiple chunks:
First the full script, which only the angsd command worked -
for FF in `cat bams`
do
F=$(basename $FF)
F_PREFIX=${F/.bam/}
angsd -i $F -anc $GENOME_REF $FILTERS -GL 1 -doSaf 1 -doCounts 1 -out ${F/.bam/} && realSFS ${F/.bam/}.saf.idx | awk -v file=$F '{print file\"\t\"(\$1+\$2+\$3)\"\t\"\$2/(\$1+\$2+\$3)}' ${F/.bam/}.ml >> goodbams.goodsites.het
done
Then
for FF in `cat bams`;
do
F=$(basename $FF)
F_PREFIX=${F/.bam/}
realSFS ${F/.bam/}.saf.idx > ${F_PREFIX}.ml
done
then
for FF in `cat bams`;
do
F=$(basename $FF)
F_PREFIX=${F/.bam/}
eval "awk -v file=$F '{print file\"\t\"(\$1+\$2+\$3)\"\t\"\$2/(\$1+\$2+\$3)}' ${F/.bam/}.ml" >> goodbams.goodsites.het
done
All performed in indev mode

how to Iterate an Array List inside 2 bash loops

I have 2 arrays in bash.
Array number 1 is the vlan subnet without the last octet.
Array number 2 is a list of octets i want to ignore, while scanning the subnet with Nmap.
lets assume every subnet has 254 pingable ip's (class c subnet)
I want the script to scan each subnet, and exclude ip's that ends with 1,2,3,252,253,254 which are Usually routers / firewalls / switches.
I manages to run 2 iterations, but failed on the if [[ $host == $host."${ignore[#]" ]] to identify the relevant ip (sunbet + ignore string)
Would really appreciate your help.
#!/bin/bash
# lets assume each subnet has 254 ips and all ignore ip's like 10.6.114.1 10.6.115.1 and 10.5.120.1
declare -a vlans=(
10.6.114
10.6.115
10.5.120
)
declare -a ignore=(
1
2
3
252
253
254
)
for vlan in "${vlans[#]}"; do
nmap -sn "$vlan" | grep Nmap | awk "{print $5}" | sed -n '1!p' | sed -e "$d" | sort > /tmp/vlan_ips.txt
readarray -t hosts < /tmp/vlan_ips.txt
for host in "${hosts[#]}"; do
check=$(echo "$host" | cut -d"." -f1-3)
if [ $host == $check."${ignore[#]}" ]; then
echo 'skipping record'
fi
done
done
This might work for you:
for vlan in "${vlans[#]}"; do
for ign in "${ignore[#]}"; do
printf '%s.%s\n' "$vlan" "$ign"
done >/tmp/ignore
nmap -n -sn "$vlan.0/24" -oG - 2>/dev/null |
grep -vwFf /tmp/ignore |
awk '/Host:/{print $2}' |
while read -r host; do
echo "$host"
done
done

Create an array with device logical name based on list of serial numbers

I'm tying to identify disks based on a list of UUID I get out of an api call.
The list of devices on the linux VM is following:
NAME="sda" SERIAL="NUTANIX_NFS_5_0_70509_a07b6add_60c9_4758_8b27_0afe77820dbd"
NAME="sdb" SERIAL="NUTANIX_NFS_18_0_625_ae748138_9bc0_4499_8068_d00a84a800b6"
NAME="sdc" SERIAL="NUTANIX_NFS_18_0_626_8a082956_a2be_42ca_a14b_7d21ed3d5a2d"
NAME="sdd" SERIAL="NUTANIX_NFS_18_0_627_6185353f_5c13_47ab_af58_b72d4d07106b"
NAME="sde" SERIAL="NUTANIX_NFS_18_0_628_fbeed366_6956_4de1_a217_487d75fd003c"
NAME="sdf" SERIAL="NUTANIX_NFS_18_0_629_019dcefb_0e1b_4086_96a9_982ae52fd88a"
NAME="sdg" SERIAL="NUTANIX_NFS_18_0_630_5d0b55e8_d0bd_4ee4_a2be_0bef88d94732"
NAME="sdh" SERIAL="NUTANIX_NFS_18_0_631_823beaed_1c2e_4203_ab5f_be294382d0c5"
NAME="sdi" SERIAL="NUTANIX_NFS_18_0_632_e4ee8620_5b53_4187_8f8c_7123ee8d3486"
NAME="sdj" SERIAL="NUTANIX_NFS_18_0_633_41551a1b_7dd9_4fd4_95bc_1fcdebb9dc85"
NAME="sdk" SERIAL="NUTANIX_NFS_18_0_634_12d517fc_e726_4512_b176_5d4075d0ecfe"
NAME="sdl" SERIAL="NUTANIX_NFS_18_0_635_d682eee4_cec0_4809_9efe_97aec7bf15d0"
NAME="sdm" SERIAL="NUTANIX_NFS_18_0_636_59ea679e_cbd3_4cf5_a974_67409b719391"
NAME="sdn" SERIAL="NUTANIX_NFS_18_0_637_5523c88e_310a_4fb6_b76f_48f624d1ce1f"
NAME="sdo" SERIAL="NUTANIX_NFS_18_0_638_0e189f7a_785d_46f1_bb56_8f422d421ecb"
NAME="sdp" SERIAL="NUTANIX_NFS_18_0_639_9143ba87_d742_4130_bbe0_2084e8ebad3f"
NAME="sdq" SERIAL="NUTANIX_NFS_18_0_640_3b823817_c2b6_49af_9a55_fc4706216501"
The list of drives I want to identify is in this format:
'ae748138_9bc0_4499_8068_d00a84a800b6'
'8a082956_a2be_42ca_a14b_7d21ed3d5a2d'
'6185353f_5c13_47ab_af58_b72d4d07106b'
'fbeed366_6956_4de1_a217_487d75fd003c'
'019dcefb_0e1b_4086_96a9_982ae52fd88a'
'5d0b55e8_d0bd_4ee4_a2be_0bef88d94732'
'823beaed_1c2e_4203_ab5f_be294382d0c5'
'e4ee8620_5b53_4187_8f8c_7123ee8d3486'
'41551a1b_7dd9_4fd4_95bc_1fcdebb9dc85'
'12d517fc_e726_4512_b176_5d4075d0ecfe'
'd682eee4_cec0_4809_9efe_97aec7bf15d0'
'59ea679e_cbd3_4cf5_a974_67409b719391'
'5523c88e_310a_4fb6_b76f_48f624d1ce1f'
'0e189f7a_785d_46f1_bb56_8f422d421ecb'
'9143ba87_d742_4130_bbe0_2084e8ebad3f'
'3b823817_c2b6_49af_9a55_fc4706216501'
I need to identify the logical name for only the UUIDs on that list in order to create a LVM volume group out of them. But I'm don't understand how to proceed from there. Anyone can propose an example ?
After removing the 's from you list of UUIDs (can be done with tr) you could use simply grep to extract the corresponding lines from your list of devices. To extract only the values of NAME="..." from these lines use cut.
grep -Ff <(tr -d \' < fileListOfUUIDs) fileListOfDevices | cut -d\" -f2
If the inputs you showed us are not stored in files but generated by commands you can use
commandListOfDevices | grep -Ff <(commandListOfUUIDs | tr -d \') | cut -d\" -f2
You are trying to extract field values from match results generated by a set of tokens. sed or awk can do the trick.
To extract the value of a field called NAME from one of the match results simply do this:
josh#linux ~ $ result='NAME="sda" FSTYPE="ext4" SERIAL="NUTANIX_...dbd"'
josh#linux ~ $ echo $result | sed -e 's/.*NAME="//; s/".*//;'
sda
To extract the value of a field called FSTYPE from the same match result:
josh#linux ~ $ echo $result | sed -e 's/.*FSTYPE="//; s/".*//;'
ext4
What if the order of the field changes? ..well the same code works.
josh#linux ~ $ result='FSTYPE="ext4" NAME="sda" SERIAL="NUTANIX_...dbd"'
josh#linux ~ $ echo $result | sed -e 's/.*NAME="//; s/".*//;'
sda
With this in mind, extraction of field values from all match results can then be processed in a loop. I have created a small script to automate the process and I am posting it here in the hope that it would be useful.
#!/bin/bash
#
# usage: doodle -F <file-containing-pattern(s)>
# doodle -P <pattern(s)>
#
if [ $# -ne 2 ]; then
echo 'invalid argument...'; exit;
else
pattern=
fi
if [ "$1" == "-F" ]; then
if [ ! -r $2 ]; then
echo "unable to read - $2"; exit
else
pattern=$(cat $2)
fi
elif [ "$1" == "-P" ]; then
pattern=$2
else
echo 'invalid argument...'; exit;
fi
if [ -z "$pattern" ]; then
echo 'invalid argument...'; exit;
fi
declare -a buffer
readarray buffer
if [ ${#buffer[*]} -gt 0 ]; then
for token in $pattern; do
for i in ${!buffer[*]}; do
match=$(echo ${buffer[i]} | sed -n "/$token/=");
if [ -n "$match" ]; then
##### Option 1 ##############################################################
# Uncomment the next line to print the same result that 'grep' would print.
#echo -e $(echo ${buffer[i]} | sed "s/$token/\\\\e[91m$token\\\\e[0m/");
##### Option 2 ##############################################################
# Uncomment the next line to print characters before the first [:space:]
#echo ${buffer[i]} | awk -F' ' '{ print $1 }';
##### Option 3 ##############################################################
# Uncomment the next line to email device-id to NSA
#TODO...
##### Option 4 ##############################################################
# Uncomment the next line to extract value of 'NAME' field
echo ${buffer[i]} | sed -e 's/.*NAME="//; s/".*//;'
##### Additional Option #####################################################
# Uncomment the next line (break command) to process one match per token
break;
fi
done
done
fi
unset buffer
To use this script, simply:
Copy the text in the above snippet into a file called doodle.
Open terminal and type:
josh#linux ~ $ chmod a+x doodle
To process tokens saved in a file called device-id.txt:
josh#linux ~ $ lsblk -nodeps -no name,serial -PS /dev/sd* | ./doodle -F device-ids.txt
To process tokens supplied as a single string:
josh#linux ~ $ lsblk -nodeps -no name,serial -PS /dev/sd* | ./doodle -P 'ae748138_9bc0_4499_8068_d00a84a800b6
8a082956_a2be_42ca_a14b_7d21ed3d5a2d
6185353f_5c13_47ab_af58_b72d4d07106b
...
3b823817_c2b6_49af_9a55_fc4706216501'
The script is very generic and you an can easily adapt it for use in related problems. You will find lots of tutorials on bash, sed and awk on the internet. There is also a comprehensive bash reference at gnu.org.

What would be command(s) to expand the file system on raspbian?

I have a number of raspberry PIs attached to various networks distributed over a large area so this will have to be a remote process. I need to expand the file system so it fills the full 8Gb (currently 2Gb). We use Puppet to distribute updates but I am not sure what the process of commands is.
I know this can be achieved locally using raspi-config but I will need to create a script or send a command to do this over the network.
raspi-config is a shell script. The section on memory expansion is listed below. Here are the basic steps:
Verify that the desired expansion is on a SD card, not external device, and not more than the two normal partitions.
Determine the exact partition and desired partition size. (parted)
Change the size of the partition in the partition table. (This usually requires a reboot to take effect.) (fdisk)
Expand the filesystem to the complete size of the partition (which was resized in step 3 above). This is setup as a shell script to run after reboot. (resize2fs)
Because there are minor differences in the size of SD cards, even different models from the same manufacturer, it would be extremely difficult to give a more specific set of commands.
#!/bin/sh
# Part of raspi-config http://github.com/asb/raspi-config
# ...
if ! [ -h /dev/root]; then
whiptail --msgbox '/dev/root does not exist or is not a symlink. Don't know how to expand" 20 60 2
return 0
fi
ROOT_PART=$(readlink /dev/root)
PART_NUM=${ROOT_PART#mmcblk0p}
if [ "$PART_NUM" = "$ROOT_PART" ]; then
whiptail --msgbox "/dev/root is not an SD card. Don't know how to expand" 20 60 2
return 0
fi
# NOTE: the NOOBS partition layout confuses parted. For now, let's only
# agree to work with a sufficiently simple partition layout
if [ "$PART_NUM" -ne 2 ]; then
whiptail msgbox "Your partition layout is not currently supported by this tool. You rae probably using NOOBS, in which case your root filesystem is already expanded anyway." 20 60 2
return 0
fi
LAST_PART_NUM=$(parted /dev/mmcblk0 -ms unit s p | tail -n 1 | cut -f 1 -d:)
if [ "$LAST_PART_NUM" != "$PART_NUM" ]; then
whiptail --msgbox "/dev/root is not the last partition. Don't know how to expand" 20 60 2
return 0
fi
# Get the starting offset of the root partition
PART_START=$(parted /dev/mmcblk0 -ms unit s p | grep "^${PART_NUM}" | cut -f 2 -d:)
[ "$PART_START" ] || return 1
# Return value will likely be error for fdisk as it fails to reload the
# partition table because the root fs is mounted
fdisk /dev/mmdblk0 <<EOF
p
d
$PART_NUM
n
p
$PART_NUM
$PART_START
p
w
EOF
ASK_TO_REBOOT=1
# now set up an init.d script
cat <<\EOF > /etc/init.d/resize2fs_once &&
#!/bin/sh
### BEGIN INIT INFO
# Provides: resize2fs_once
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5 S
# Default-Stop:
# Short-Description: Resize the root filesystem to fill partition
### END INIT INFO
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting resize2fs_once" &&
resize2fs /dev/root &&
rm /etc/init.d/resize2fs_once &&
update-rc.d resize2fs_once remove &&
log_end_msg $?
;;
*)
echo "Usage $0 start" >&2
exit 3
;;
esac
EOF
chmod +x /etc/init.d/resize2fs_once &&
update-rc.d resize2fs_once defaults &&
if [ '$INTERACTIVE" = True ]; then
whiptail --msgbox "Root partition has been resized.\nThe filesystem will be enlarged upon the next reboot" 20 60 2
fi

How to catch signals from a shell script which is executing a file which may throw it?

I have a shell script, which is executing a program fuseIO which is basically a C program.
Ths idea is, this executable fuseIO may throw a SIGABRT by an abort( ) call inside it, in which case, the while loop should exit.
How to accomplish that?
i=0
while [ $i != 10 ]
do
echo "************ Iteration: $i *********\n" 2>&1 |tee -a log.txt
./fuseIO 2>&1 | tee -a log.txt // This may throw SIGABRT
i=`expr $i + 1`
sleep 1
done
In part, see Exit status codes greater than — possible? The WIFSIGNALED stuff tells you that a process was signalled, but there's a problem for the shell encoding that, and it does it by encoding a signalled exit status as 128 + signal number (129 for HUP, 130 for INT, etc). To demonstrate shell and signal exit statuses:
$ cat killme.sh
#!/bin/bash
kill ${1:-"-INT"} $$
$ ./killme.sh -HUP; echo $?
Hangup: 1
129
$ ./killme.sh -TERM; echo $?
Terminated: 15
143
$ ./killme.sh -QUIT; echo $?
0
$ ./killme.sh -PIPE; echo $?
141
$ ulimit -a
core file size (blocks, -c) 0
...
$
This more or less justifies my '128+signum' claim (the -QUIT behaviour is unexpected, but explainable after a fashion — it normally dumps core, but didn't because ulimit has them disabled).
In bash, you can get 'a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command)' via the array $PIPESTATUS. For example:
$ ./killme.sh | exit 31
$ echo ${PIPESTATUS[*]}
130 31
$
This corresponds to the 130 exit status for SIGINT (2) plus the explicit exit status 31. Note the notation: ${PIPESTATUS[0]} with the braces around the indexing. Double quotes and things work like $* vs $# vs "$*" vs "$#" for getting all the values in the array.
Applied to your two-part pipeline, you should be able to test:
if [[ ${PIPESTATUS[0]} == 134 ]]
then : FuseIO crash with SIGABRT
fi
Without the | tee, you can simply test $?:
if [[ $? > 128 && $? < 160 ]]
then : died a signalled death (probably)
else : died an ordinary death
fi
The 160 here is also an informed guess; it should be 128+SIGRTMAX. Note that if a process does exit 135, it will be treated as if it was signalled (even if it does not).

Resources