2

I think generate temp file may slower and if user press ctrl+c the temp file will become garbage.

Here is my original code

for f in bin/* ; do
  ldd $f 2>/dev/null | awk '{print $1}'
done | sort -u | grep -v -e '^not$' -e 'ld-linux' > list.1
while read soname ; do
  process_so_name $soname
done < list.1

Is it possible to remove the temp file list.1?

vahid abdi
  • 9,636
  • 4
  • 29
  • 35
Daniel YC Lin
  • 15,050
  • 18
  • 63
  • 96
  • I think you mean to ask "Can I rewrite this code so it doesn't use a temp file on disk", right? – Floris Jan 26 '13 at 04:17
  • I believe the key to your problem is the `xargs` command; see [this earlier SO article](http://stackoverflow.com/questions/2711001/how-to-apply-shell-command-to-each-line-of-a-command-output) – Floris Jan 26 '13 at 04:21

4 Answers4

5

Just do it without a temp file. Pipe the result of the last grep into the while.

You can hook into SIGINT to detect Ctrl+C, but why worry if you don't need to? You still won't be able to hook into SIGKILL.

for f in bin/* ; do
  ldd $f 2>/dev/null | awk '{print $1}'
done | sort -u | grep -v -e '^not$' -e 'ld-linux' | while read soname ; do
  process_so_name $soname
done

You can make this look more recognizable by placing the loops in functions (you can do this in a script file or right in the shell):

step_1() {
  for f in bin/* ; do
    ldd $f 2>/dev/null | awk '{print $1}'
  done
}

step_2() {
  while read soname ; do
    process_so_name $soname
  done
}

step_1 | grep -v -e '^not$' -e 'ld-linux' | step_2

To hook into SIGINT, do something like this:

trap "echo SIGINT; rm -f tempfile; exit -1" INT

To hook into SIGTERM (see comments underneath), do this:

trap "echo SIGTERM; rm -f tempfile; exit -1" EXIT
Mihai Danila
  • 2,229
  • 1
  • 23
  • 28
2

In addition to @MihaiDanila 's correct answer,

If you wan't to reuse some statistic value in your main loop, you have to re-order your script and use Process Substitution

total=0
processed=0
while read soname ; do
  ((total=total+1))
  process_so_name $soname && ((processed=processed+1))
done < <(
    for f in bin/* ; do
      ldd $f 2>/dev/null | awk '{print $1}'
    done |
      sort -u |
      grep -v -e '^not$' -e 'ld-linux'
)
printf "Total file %d, processed ok: %d, last filename: '%s'" \
    $total $processed $soname

Syntax using pipe, like ... grep -v | while read soname will do a fork after pipe, so the environment of main loop will be dropped at end.

See: man -Len -Pless\ -i\ +/^\\\ *process\\\ substitution$ bash

F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
1

like @M

another way without tempfile

function func_name(){
for f in bin/* ; do
ldd $f 2>/dev/null | awk '{print $1}'
done | sort -u | grep -v -e '^not$' -e 'ld-linux'
}

while read soname ; do
process_so_name $soname
done < <(func_name)

test

function func_name2(){
echo 1
echo 2
}

while read soname ; do
echo $soname
done < <(func_name2)
farmer1992
  • 7,816
  • 3
  • 30
  • 26
0

Does the following work for you?

for f in bin/* ; do
  ldd $f 2>/dev/null | awk '{print $1}'
done | sort -u | grep -v -e '^not$' -e 'ld-linux' | xargs -n 1 process_so_name
Floris
  • 45,857
  • 6
  • 70
  • 122
  • Compact, but harder to adapt to files with spaces in their names than the more verbose `while`. – Mihai Danila Jan 26 '13 at 04:48
  • 1
    to match up with the original code, use the `-n 1` option for xargs – glenn jackman Jan 26 '13 at 04:48
  • @MihaiDanila, to handle files with spaces, use `xargs -I {} process_so_name {}` – glenn jackman Jan 26 '13 at 04:49
  • @glennjackmanCorrect. I've also seen a lot in the xargs man page about how to cause the command upstream of xargs to use a `\0` to delimit records in order to allow xargs to find the same via `-0`. Our asker is safe from that complication due to his precise requirement of calling with one argument at a time, but not with `xargs -n 1`. – Mihai Danila Mar 25 '13 at 02:51
  • 1
    I do love the xargs, that is arguably the most important for the OP to learn here. Hmm, has it been eight years? :) – Mihai Danila Jul 07 '21 at 22:35