如何在KSH脚本中用Sed仅替换非嵌套/* */内的//注释?
Hey there, I see you're dealing with a tricky comment conversion issue when migrating your Pro C code from Windows to Linux. Your current sed script is replacing all // comments—even those nested inside /* */ blocks—which creates broken comment structures like /* /* some comments */ code; code; */ that throw off compilers. Let's fix this properly.
Why Your Current Sed Script Fails
Sed operates line-by-line and can't track state (like whether you're inside a multi-line comment block). It has no way to distinguish between a // in regular code vs. one nested inside an existing /* */ comment, leading to those invalid nested comment messes. We need a tool that can track this state, and awk is perfect for the job.
The Awk Solution
This awk script will only replace // comments that are not inside /* */ blocks, while handling multi-line comments correctly:
#!/usr/bin/awk -f BEGIN { in_block_comment = 0 # Track if we're inside a /* */ comment } { current_line = $0 remaining_line = current_line while (length(remaining_line) > 0) { if (!in_block_comment) { # Find positions of // and /* in the remaining line pos_double_slash = index(remaining_line, "//") pos_block_start = index(remaining_line, "/*") # Prioritize // if it comes before /* if (pos_double_slash > 0 && (pos_block_start == 0 || pos_double_slash < pos_block_start)) { # Replace // with /* ... */ print substr(remaining_line, 1, pos_double_slash - 1) "/*" substr(remaining_line, pos_double_slash + 2) "*/" remaining_line = "" } # Handle starting a block comment else if (pos_block_start > 0) { print substr(remaining_line, 1, pos_block_start + 1) remaining_line = substr(remaining_line, pos_block_start + 2) in_block_comment = 1 } # No comments left, print the rest else { print remaining_line remaining_line = "" } } else { # Look for the end of the block comment pos_block_end = index(remaining_line, "*/") if (pos_block_end > 0) { print substr(remaining_line, 1, pos_block_end + 1) remaining_line = substr(remaining_line, pos_block_end + 2) in_block_comment = 0 } # No end found, print the whole line (still in block comment) else { print remaining_line remaining_line = "" } } } }
How This Script Works
- State Tracking: The
in_block_commentvariable keeps track of whether we're inside a/* */comment (1 = yes, 0 = no). - Line Processing: For each line, we process it in chunks:
- When not in a block comment, we check for
//first—if it appears before any/*, we replace it with/* ... */. - If we hit a
/*, we mark ourselves as being in a block comment and continue processing the rest of the line. - When inside a block comment, we only look for
*/to exit the block—any//inside is ignored entirely.
- When not in a block comment, we check for
Using the Script
- Save the script above as
convert_comments.awk. - Make it executable:
chmod +x convert_comments.awk - Run it on your Pro C files (replace
$pathwith your actual directory):
We use a temp file to avoid overwriting the original file before confirming the conversion works.for file in "$path"/*.pc; do ./convert_comments.awk "$file" > "$file.tmp" && mv "$file.tmp" "$file" done
Key Notes
- Handles multi-line
/* */comments correctly (even if they span multiple lines). - Ignores
//comments nested inside/* */entirely—no broken nested comments. - If your code has
//inside string literals (likeprintf("//hello");), this script will incorrectly replace them. If that's a case you need to handle, we can tweak the script to check for string boundaries, but it adds complexity. Let me know if you need that!
内容的提问来源于stack exchange,提问作者Mario Esposito

