0

I have a little bash snippet I'm working on:

$ stat --printf=%A\|%U\|%G\|%s\|%y\|%N'\n' /usr/src/linux-headers-4.4.0-124/zfs/cmd/zhack
drwxr-xr-x|root|root|4096|2018-05-17 05:54:49.361904361 -0600|'/usr/src/linux-headers-4.4.0-124/zfs/cmd/zhack

The date is rather ugly so I'd like to use sed (or whatever works) to delete everything after the first space up to the following |. Of course if the stat command can print the date normally that works too!

Any tips for the sed challenged?

dessert
  • 41,116

2 Answers2

3

With sed:

$ stat --printf='%A|%U|%G|%s|%y|%N\n' /etc/profile | sed 's/ [^|]*//'
-rw-r--r--|root|root|575|2015-10-23|'/etc/profile'

Which simply replaces a space followed by non-| characters with nothing.

dessert
  • 41,116
muru
  • 207,970
  • "simply" is in the hands of the coder :). Looks good. The file name could have a space but is unlikely to have a pipe character in it so I think I'm good now. Thanks. – WinEunuuchs2Unix May 23 '18 at 01:45
  • @WinEunuuchs2Unix both cases do not matter, since | will always come between the date (which also always includes a space) and the filename using the format you have given. – muru May 23 '18 at 01:46
  • Yup. Script is finished now. Coming to a screen soon near you. I'll put in a credit note for your sage sed help. – WinEunuuchs2Unix May 23 '18 at 02:34
2

With bash

$ a=$(stat -c'%A|%U|%G|%s|%y|%N' /etc/profile) ; echo ${a/ *|/|}
-rw-r--r--|root|root|575|2017-09-22|'/etc/profile'

This is bash’s Parameter Expansion, more precisely Pattern Substitution, see man bash/EXPANSION/Parameter Expansion. I also took the freedom to simplify your command line a bit.

With awk

$ stat -c'%A|%U|%G|%s|%y|%N' /etc/profile | awk -v{O,}FS=\| '{sub(/ [^|]+/,"",$5)}1'
-rw-r--r--|root|root|575|2017-09-22|'/etc/profile'

This is slightly longer, but actually the most accurate solution: It changes explicitly the fifth field only so that spaces in file and user names (expect the unexpected) won’t be a problem. Compare:

$ a="-rw-r--r--|ro ot|ro ot|575|2017-09-22 17:35:19.337510248 +0200|'/etc/pro fi|le'"
$ sed 's/ [^|]*//' <<<$a
-rw-r--r--|ro|ro ot|575|2017-09-22 17:35:19.337510248 +0200|'/etc/pro fi|le'
$ echo ${a/ *|/|}
-rw-r--r--|ro|le'
$ awk -v{O,}FS=\| '{sub(/ [^|]+/,"",$5)}1' <<<$a
-rw-r--r--|ro ot|ro ot|575|2017-09-22|'/etc/pro fi|le'

The username should not contain a bar | though – however, you could take care of that eventuality as well:

$ b=$(awk -F\| '{print NF-1}' <<<"ro||ot") # how many bars again?
$ a="-rw-r--r--|ro||ot|ro||ot|575|2017-09-22 17:35:19.337510248 +0200|'/etc/pro fi|le'"
$ awk -v{O,}FS=\| '{sub(/ [^|]+/,"",$'$((5+b*2))')}1' <<<$a
-rw-r--r--|ro||ot|ro||ot|575|2017-09-22|'/etc/pro fi|le'
dessert
  • 41,116