Home > Mobile >  How can I filter out files with a shebang from those passed to xargs?
How can I filter out files with a shebang from those passed to xargs?

Time:07-08

TL;DR

I'm trying to write a simple script that compiles all .swift files in a given folder and any of it's subfolders, but which excludes those files that start with a shebang.

The Details

I'm trying to write a simple utility that will let me compile multiple Swift files into a single compiled output without requiring any advanced IDEs or project files, etc. The folder structure itself will be the project's definition with the root being wherever I find a main.swift file.

Assuming I've already found main.swift and am in the according directory, starting with the find command, I can find all relevant Swift files like so...

find * -type f -name "*.swift"

Thanks to another answer here, by appending -print0 and feeding that to xargs -0, they can all be sent to swift compiler in one fell swoop, like so...

find * -type f -name "*.swift" -print0 | xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"

Note: thanks to the use of -print0 on the find command and xargs -0 on the other side, all n arguments are passed in at the same time to one execution of xcrun, not n executions of xcrun with one argument each. There is only one compilation and one single output file.

The issue is if any of those Swift files are set up as Swift script files (i.e. those that start with a shebang), the compiler rejects them. They're also most likely to contain top-level statements, something the compiler also doesn't like unless they are in main.swift.

For instance, if this is in the file someutil...

#! /usr/bin/env swift
print("Hello from Swift!")

...and you ran chmod x someutil, you could now execute that Swift file like any other shell script so long as it's reachable in the path.

echo Here we go!
someutil
echo Done!

Output

Here we go!
Hello from Swift
Done!

However, if you send that file to the compiler, it will complain both about the shebang and about the top-level statements not being in main.swift.

As such, I'm trying to filter out any of the found files which start with a shebang, using that basically as the identifier of Swift scripts to be excluded.

I've seen a lot of grep tutorials for how to include only those files, but can't find any that exclude them, especially since the above code also depends on the -print0 of the find command itself (meaning I can't easily do the filtering elsewhere.)

So is this possible?

CodePudding user response:

May be with a grep command between find and xcrun:

find * -type f -name "*.swift" -print0 | xargs -0 grep -L '^#! /usr/bin/env swift$' -Z | xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"

grep option:

  • -L: Suppress normal output; instead print the name of each input file from which no output would normally have been printed
  • -Z: Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name.

CodePudding user response:

You can run a loop with output of find command and run a grep inside:

while IFS= read -rd '' f; do
   grep -qF '#! /usr/bin/env swift' "$f" || printf '%s\0' "$f"
done < <(find * -type f -name "*.swift" -print0) |
xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"
  • Related