0

Using files where is stored some data, I'd like read into these files and print 5 specific lines that match a pattern, in other files. But if the files are not corrects, I'd like to print 5 lines containing whatever message ("ERROR" for instance), to differentiate and to know which file is good or not.

Here is how I'm doing it:

if grep -q 'PATTERN' outputfile;
    then
     grep --color 'ANOTHER_PATTERN' outputfile > tmpfile
   else
     printf 'ERROR %.0s\n' {1..5} > tmpfile
fi

So, my question is how does the commandprintf 'ERROR %.0s\n' {1..5} really works ? The code is actually working but I'm not comfortable using commands that I don't fully understand.

I know %s is used to print strings, \nis for a newline but I don't know why we need to use the .0s. I guess it's a "trick" to print a blank space next to "ERROR" instead of the number (1,2..,5) because if I just use %s\n {1..5} I obtain:

ERROR 1
ERROR 2 
...

and so on until 5. My second question would be : How can I print 5 lines with the ERRORmessage without using this ? Thanks in advace for any tips.

1
  • The blank space next to the word "ERROR" comes from the space you placed after the word "ERROR" in the string ERROR %.0s. The string %.0s is a format that tells you how to print strings (s). the part .0 tells how many characters of the string should be printed. In this case ZERO. See man printf and man 3 printf Commented Jul 23, 2019 at 21:54

2 Answers 2

1

Printf variables take the form:

%[parameter$][flags][width][.precision][length]type
  • precision: integer minimum string length, max floating points digits after decimal, or max number of characters in the string. Prefixed by .

Thus .0s prints 0 characters of your string, omitting it.

If you really want to print something 5 times, the most basic way is a for loop

for i in {1..5}; do echo "ERROR"; done
Sign up to request clarification or add additional context in comments.

2 Comments

I thought about a for loop yes, but I wanted to understand this "printf" command. Thanks for the help and explanations ! :)
@Pierre-LouisLEFEBVRE, if one of these answers solved your problem, consider accepting it by clicking the grey checkmark under the voting icons. It will mark the question as solved so other people do not spend more time on it, and you'll gain some stack overflow points.
1

If receiving more arguments than the format specify, the format string will repeat until there is no more argument.

{1..5} generate a sequence of 5 integers arguments

You can write your code with same results as:

printf 'ERROR %.s\n' _ _ _ _ _ > tmpfile

Or with an explicit loop redirected to tmpfile

for i in _ _ _ _ _; do echo 'ERROR'; done >tmpfile

The printf method is the most efficient as it executes only one Bash statement versus multiple ones with a for loop.

Remember Bash has no JIT compiler, so it parse each command each times in a loop.

3 Comments

Yes, it's maybe easier like this indeed. I'll go for the echo option. Many thanks :)
seq is nowhere in the POSIX spec. If one wants to call out a portable way to count in shell (relying only on standard-mandated functionality), one ends up with something like i=0; while [ "$i" -lt 10 ]; do ...; i=$((i + 1)); done.
@CharlesDuffy Indeed seq is GNU CoreUtils and not POSIX. I removed it from my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.