6

context: https://stackoverflow.com/a/47348104/15603477

printf -v pasteargs %*s 16
paste -d\  ${pasteargs// /- } < <(seq 1 42)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40 41 42

paste -d, --delimiters=LIST reuse characters from LIST instead of TABs

${parameter/pattern/string}

The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. The match is performed according to the rules described below (see Pattern Matching). If pattern begins with ‘/’, all matches of pattern are replaced with string.

after checked with manual.

  1. what does ${pasteargs// /- } do.
  2. I do know %s refers to printf argument. But %*s 16 I don't know.
  3. Even I quoted manual, still not sure paste -d\

2 Answers 2

6
  1. printf %*s 16 means: print 16 spaces. See this answer for further explanation. So now pasteargs is a variable with a value of 16 spaces.

  2. ${pasteargs// /- } means: Replace all occurrences of (space) in the variable with - (in other words: add a hyphen before each space in the variable). As you quoted from the manual:

    If pattern begins with ‘/’, all matches of pattern are replaced with string.

    And the pattern here is / , which means: all matches of space. So now the value of pasteargs is 16 hyphens separated by spaces.

  3. Regarding the paste command, you first need to understand that it's followed by 16 hyphens, meaning 16 streams. Basically it will merge every 16 consecutive lines into one line. By default, when those lines are merged, they are delimited by tabs. So paste -d\ (notice the trailing space after the backslash) means to separate the lines by spaces (\ ) instead of tabs.

To summarize, this command (as advertised) just merges each 16 consecutive lines from the input into one line separated by spaces.

4
  • The wording in the documentation ("begins with") implies that the slash is part of the pattern to replace, though, doesn't it? So all occurrences of / (not just space) should be replaced. Perhaps "is preceded by" would fit the actual behavior better.
    – DonHolgo
    Dec 23, 2021 at 15:34
  • @DonHolgo It's imprecise wording, but no one misunderstands it. And "preceded by /" is true whether you write /pattern or //pattern.
    – Barmar
    Dec 23, 2021 at 15:38
  • 1
    printf %*s 16 only means print 16 spaces if there is no file whose name starts with % and ends in s in the current directory, and in the case of bash if the nullglob and failglob options are not enabled. Dec 23, 2021 at 17:28
  • You may want to explain the seq as well. Dec 23, 2021 at 20:21
4

Best thing is to try in a sandbox (test) environment (virtual machine?) and see the results. Your questions don't follow the order given in the example, so

  1. man printf:

    Field width ... Instead of a decimal digit string ... one may write "*" ... to specify that the field width is given in the next argument, ... which must be of type int.

so printf %*s 16 with a missing to-be-printed argument prints 16 spaces.

  1. That "parameter expansion" converts the before-printed 16 spaces to 16 dash-space sequences.

  2. see above

  3. That's just an escaped space in lieu of the default <TAB> delimiters

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.