3

I am working on a script that will process a .zip file received from clients. It is common in my job to want the contents of the .zip file received listed within a log file as a means of validation. I have been able to extract the list of files from my test files and insert the list of files within a log file.

I am now attempting to neaten the log file up by adding newline and tabs before the names of the extracted files in the log file. I have come closest with the commented line in the sample below but it only adds tabs to a single line of the output. I next thought about using SED but my poor knowledge of it just results in a blank line in the log file...

    log_message "-------- Extracting files"
    zipflist="`unzip -Z1 $file`"
    log_message "Files found in received zip file..."
#    log_message $'\n\t\t\t'"$zipflist"
    log_message `sed '1 s/^/$'\t'"$zipflist"/' `

The "log_message" function passes strings to a file with a pre-pended date time.

Here is what the best results I have gotten look like so far:

2023-12-29 09:31:44: Files found in received zip file...
2023-12-29 09:31:44:
                        loremipsum.pdf
loremipsum.txt
dummy_report.xml

I would prefer the output to look like this:

2023-12-29 09:31:44: Files found in received zip file...
2023-12-29 09:31:44:
                        loremipsum.pdf
                        loremipsum.txt
                        dummy_report.xml

Is there a way this can be accomplished with SED, tr or other base utility in RHEL? I cannot install anything not company approved so I prefer to work with what I have. (Saves the hassle of approvals)

4
  • For which shell are you writing this script? Commented Dec 29, 2023 at 17:18
  • And how you are trying so far? Commented Dec 29, 2023 at 18:32
  • This is for bash shell 4.4.20(1)-release. I have tried using SED, TR and AWK. Sorry, after spending all day yesterday trying numerous versions that I found across the internet including here, I cannot recall all I have tried. My code sample included here is what I thought would be most promising. Commented Dec 29, 2023 at 21:28
  • Get out of the old backtick habit and learn to use $(). You'll thank me the next time you need to use nested command substitution. Commented Dec 30, 2023 at 23:37

3 Answers 3

5
% str=$'foo\nbar\ndoo\n'
% printf "%s" "$str" |sed -e $'s/^/\t/'
    foo
    bar
    doo

(If you're not going to do anything else with the list, just do unzip | sed directly without the var.)

2
  • Note the value stored by var=$(cmd) or var=`cmd` does not include any trailing newline(s). However at least for GNU sed, which RHEL will have, this doesn't matter. Commented Dec 30, 2023 at 1:23
  • yes, or if you print the value with echo it adds the final newline again, papering over the difference. Meaning what I did in the answer here is slightly different Commented Dec 30, 2023 at 14:43
3

In the bash shell, you can do it to lines stored as elements of an array variable as follows. First, read the zipinfo output into a shell array instead of a string scalar variable, and then use the array form of parameter expansion ${parameter/pattern/string} to prefix each element.

So for example, given a simple log function

log_message() { printf '%s\n' "$@"; }

then

readarray -t zipflist < <(unzip -Z1 "$file")
log_message "${zipflist[@]/#/$'\t'}"
3

You could just use a "here string":

sed -e $'s/^/\t\t\t/' <<< "$zipflist"

This would be appropriate if the list of files (with newlines separating them) were already present in a shell variable.

However, since you're getting that into a shell variable from a command, better would be to just do that formatting directly in the original command:

zipflist="$(unzip -Z1 "$file" | sed $'s/^/\t\t\t/')"

The problem you'd then have is with the first line not lining up. You could handle that by prepending a newline like so:

log_message "-------- Extracting files"
zipflist="$(unzip -Z1 "$file" | sed -e $'1i\\\n' -e $'s/^/\t\t\t/g')"
log_message "$zipflist"

This should produce exactly the output you indicated as desirable in your question.


Some added commentary: I wonder, what is this log_message command? In general, you might be better served by cleaning up the logic of your logging helper function so you can pipe stuff directly to it and have it handle it correctly, prepending the timestamp to EACH line of the input, as is usual for logs. If this is a Linux system you might use the logger command and thereby bypass the need for fiddling with whitespace like this. logger by default writes to the syslog, but you can also turn that part off and use its standard error.

A good follow-up question might be something like, "What is a clean fast way to prepend each line of my script output with the current timestamp?" (Assuming of course you do some homework and make some effort before asking outright.)

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.