Home > database >  change the separator of a paste commande
change the separator of a paste commande

Time:07-14

I have a probleme to parse the result of my commande :

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

which give me this :

c37967f401d16fa37736cbe08809d3d66c8f516a  /etc/vmware-tools/resume-vm-default 1aae06b3e3db93584b27ddf24ecd58e7a080f33c160f0186ec9b50ab32bc9a92  /etc/vmware-
tools/resume-vm-default 4.0K    /etc/update-manager/release-upgrades

But I don't want spaces to separate them because it's impossible to parse them because of the spaces that appears in the file name.

how can i get something like this?

md5; sha1; sha256, size, path

I don't find how to change the separator between my values.

I tried :

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

but it print only the path...

I tried :

 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

which is almost why in want. but mistake appears like ^ in my sha1...

Also I don't want to get the file path 5 times.

do 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 returns a tons of error.

CodePudding user response:

Instead of your complicated use of xargs and paste you could use a simpler bash loop:

$ declare -a r s t u
$ while IFS= read -d '' file; do
    r=( $(md5sum "$file") )
    s=( $(sha1sum "$file") )
    t=( $(sha256sum "$file") )
    u=( $(du -lh "$file") )
    printf "%s; %s; %s, %s, %s\n" "${r[0]}" "${s[0]}" "${t[0]}" "${u[0]}" "$file"
done < <( find / -type f -not \( -path '/dev/*' -or -path '/proc/*' -or -path '/sys/devices/*' \) -print0 )

The r, s, t and u indexed arrays are just a way to easily isolate the first word of a command's output.

Note that the output format you chose is probably not that easy to parse because it mixes semi-colons and commas and adds a space after them. Not mentioning the possibility of file names with semi-colons, commas or newlines. A cleaner output format would stick with the NUL separator (the only character that you cannot find in a file name):

$ declare -a r s t u
$ while IFS= read -d '' file; do
    r=( $(md5sum "$file") )
    s=( $(sha1sum "$file") )
    t=( $(sha256sum "$file") )
    u=( $(du -lh "$file") )
    printf "%s\0%s\0%s\0%s\0%s\0" "${r[0]}" "${s[0]}" "${t[0]}" "${u[0]}" "$file"
done < <( find / -type f -not \( -path '/dev/*' -or -path '/proc/*' -or -path '/sys/devices/*' \) -print0 )

CodePudding user response:

I am not personally fond of long "one-liners" that are hard to read later when you inevitably need to do the same thing again, or maintain/edit it.

  while IFS= read -d $'\0' -r filename; do
    md5="$(md5sum "$filename")"
    sha1="$(sha1sum "$filename")"
    sha256="$(sha256sum "$filename")"
    durpt="$(du -lh "$filename")"
    printf "%s;%s;%s;%s;%s\n" "$filename" "${md5% *}" "${sha1% *}" "${sha256% *}" "${durpt%$'\t'*}"
  done < <( find / -type f -not \( -path '/dev/*' -or -path '/proc/*' -or -path '/sys/devices/*' \) -print0 )

This separates the subshell calls out to variable assignments so that formatting and editing them is easier later. I cleaned the filenames &c off the hashes and the end of the du output, and added the filename as a field at the beginning.

  • Related