1

For our IOS project I want to merge old style pragma lines like

#pragma mark -
#pragma mark Getters

into single lines like

#pragma mark - Getters

After doing some research on the Internet, I came up with the following terminal command:

find . -type f -exec awk '{if (sub(/#pragma mark -$/,"#pragma mark -")) printf "%s", $0; else print $0}' {} > {} \;

This is be the first command which would merge the two lines. I would then use another one to delete the redundant #pragma mark - characters. However, above command does not terminate. It does not change anything, at all.

Bastian
  • 4,638
  • 6
  • 36
  • 55
  • 1
    You can't `awk file > file` (what command you use doesn't matter) the terminal truncates the output file *immediately* so your command never sees any file contents. – Etan Reisner Feb 26 '15 at 14:59
  • @EtanReisner Thank you for this hint. Since I am a complete newbie to bash magic, I do not know how to circumvent this problem. – Bastian Feb 26 '15 at 15:03
  • 2
    You operate on one file and output to another and then move the new file over the old file. – Etan Reisner Feb 26 '15 at 15:03
  • USe xargs instead of exec –  Feb 26 '15 at 15:46

3 Answers3

3

When you press enter, the shell first processes any redirections, in this case > {}. That happens before the shell creates the process for find since it needs to connect the output of the find process to {}. Which means you should find a file {} in the current folder.

I think you're better off with a loop in this case:

find . -type f -print0 | while IFS= read -r -d $'\0' file
do
   awk ... "$file" > "$file"
done

but there is a catch: Again, the shell will first do the redirection. That means it will create an empty $file as output for awk and then start awk which will then commence to read said empty file. A more simple way to achieve the same thing would be echo -n > "$file".

So you really need to write to a temporary file and then rename:

find . -type f -print0 | while IFS= read -r -d $'\0' file
do
   awk ... "$file" > "$file.tmp" && mv "$file.tmp" "$file"
done

And make sure you have a backup of everything before you run the command because it might go horribly wrong. For example, if you have a hidden folder from your version control, find will go in there and awk will then destroy a few important bits.

PS: If you use an IDE, enable regular expressions and search for #pragma mark -\n#pragma mark Getters. Now you can replace the two lines with a single one and your IDE will make 95% sure that the string isn't replaced in places where you don't want it to happen.

gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Although I suppose that the posted code works flawlessly, your last hint concerning the IDE's abilities was crucial. With that information I searched for multi-line search/replace in XCode and found this great SO entry: http://stackoverflow.com/questions/5522258/how-to-replace-multi-new-line-with-single-new-line-in-xcode-using-find-replace – Bastian Feb 26 '15 at 15:37
  • Related: http://stackoverflow.com/questions/7039130/bash-iterate-over-list-of-files-with-spaces – Aaron Digulla Feb 27 '15 at 16:39
1

If your awk version is >=4.1.0, you can do

find . -type f -exec awk -i inplace '{if (sub(/#pragma mark -$/,"#pragma mark -")) printf "%s", $0; else print $0}' {} \;
Corentin Peuvrel
  • 310
  • 1
  • 2
  • 9
  • Useful option, but the `awk` command you copied from the question is not right, and neither the `find` without, at least, escaping curly braces. – Birei Feb 26 '15 at 20:35
0

This should work:

#!/usr/bin/python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import re
import sys

array = [] pragmas = [] with open("my.file", "r") as ins:
    i = 0
    lastPragmaLine = 0
    for line in ins:
        m = re.search(r'^\s*[#]\s*pragma\s+mark\s+(.*\S)\s*$', line)
        if m:
           pragmas.append(m.group(1))
           lastPragmaLine = i
        else:
           array.append(line.rstrip('\n\r'))
           i += 1
    array.insert(lastPragmaLine, '#pragma mark ' + ' '.join(pragmas))

with open("my.output.file", "w") as ins:
    for line in array:
        print(line, file=ins)

Copy the contents into foo.py and run python foo.py on your machine (assuming it has a python interpreter, which most do).

djhaskin987
  • 9,741
  • 4
  • 50
  • 86