bashawkfindpastexargs

how to use awk in bash -c do the ' ' in awk ' ' doesn't break the bash -c ' ' bash?


At the begining i have this scipt that put the stdout in a file.txt :

find .. -type f -not \( -path '/dev/*' -or -path '/proc/*' -or -path '/sys/devices/*' \) -print0 |
  xargs -0 bash -c 'paste -d ";" <(md5sum "$@") <(sha1sum "$@") <(sha256sum "$@") <(du -lh "$@")' bash 

but it returns the path 5 times with spaces which makes things hard to parse.

So I did this :

 find / -type f -not \( -path '/dev/*' -or -path '/proc/*' -or -path '/sys/devices/*' \) -print0 |
  xargs -0 bash -c `paste -d ";" <(md5sum "$@" | awk "{print $1}") <(sha1sum "$@" | awk "{print $1}") <(sha256sum "$@" | awk "{print $1;}") <(du -lh "$@"| awk "{print $1;}")` bash

But it's not working

How would you do ?

I just don't know how to get : md5;sha1;sha256;size;path;md5;sha1;sha256;size;path;md5;sha1;sha256;size;path;md5;sha1;sha256;size;path;md5;sha1;sha256;size;path;md5;sha1;sha256;size;path; etc ...

Basically, all on 1 line.


Solution

  • In your second command, you used backtick "quotes" for xargs -0 bash -c `...` bash. Those behave like $(...) so the command string was executed before find | xargs even started.
    And in that command string, bash replaced $1 before awk even started.

    Command strings with nested quotes are easier to write in multiple steps using one helper variable for each level of quoting, but since you are using bash, you can export a function instead, which makes things trivial.

    Your command correctly wrapped

    f() {
      paste -d ";" \
        <(md5sum "$@" | awk '{print $1}') \
        <(sha1sum "$@" | awk '{print $1}') \
        <(sha256sum "$@" | awk '{print $1}') \
        <(du -lh "$@" | awk '{print $1}')
    }
    export -f f
    find / -type f -not \( -path '/dev/*' -or -path '/proc/*' -or -path '/sys/devices/*' \) -print0 |
    xargs -0 bash -c 'f "$@"' bash
    

    Slightly improved and adapted to your needs

    As you wanted, we can print all fields for all files in a single line by replacing (tr) each \n by an ;. The paths are not quoted in any way. If they contain a ; or linebreak, parsing the result could be difficult. If you need some form of quoting try printf %q or sed [-z] 's/.../.../g'.

    f() {
      paste -d ";" \
        <(md5sum "$@" | cut -c 1-32) \
        <(sha1sum "$@" | cut -c 1-40) \
        <(sha256sum "$@" | cut -c 1-64) \
        <(du -lh "$@" | cut -f1) \
        <(printf '%s\n' "$@") |
      tr '\n' ';'
    }
    export -f f
    find / \( -path /dev/ -o -path /proc/ -o -path /sys/devices/ \) -prune -o \
      -type f -exec bash -c 'f "$@"' bash +