如果一個.cpp或.h文件包含#includes(例如#include「ready.h」),我需要創建一個文本文件,其中包含這些文件名。由於ready.h可能有自己的#includes,因此必須遞歸調用。不知道如何做到這一點。如何使用Perl,awk或sed進行遞歸調用?
回答
在Perl中,遞歸是直截了當:
sub factorial
{
my $n = shift;
if($n <= 1)
{ return 1; }
else
{ return $n * factorial($n - 1); }
}
print factorial 7; # prints 7 * 6 * 5 * 4 * 3 * 2 * 1
隨口說說,我能想到的只有兩個需要照顧的事情:
- 在Perl中,變量是由默認的全局,因此,靜態默認。既然你不想讓一個函數調用的變量踐踏另一個變量,你需要確保本地化你的變量,例如通過使用
my
。 - 原型和遞歸有一些限制。如果要使用原型(例如
sub factorial($)
而不是sub factorial
),則需要在之前提供原型的函數定義,以便它可以在函數體內使用。 (或者,您也可以使用&
當你調用遞歸函數;這將阻止原型被應用。)
並不完全清楚自己想要的顯示是什麼樣子,但基本會被稱爲腳本follow_includes.pl:
#!/usr/bin/perl -w
while(<>) {
if(/\#include "(\S+)\"/) {
print STDOUT $1 . "\n";
system("./follow_includes.pl $1");
}
}
運行它想:
% follow_includes.pl somefile.cpp
如果你想隱藏任何重複的包括運行它想:
% follow_includes.pl somefile.cpp | sort -u
通常你會想要某種樹形打印。
謝謝,這個作品很棒。 – Exeter 2013-04-29 02:35:43
如果你喜歡它,請選擇我的答案:) – OneSolitaryNoob 2013-07-29 06:13:40
@OneSolitaryNoob的解決方案可能會正常工作,但有一個問題:對於每個遞歸,它啓動另一個進程,這是非常浪費的。我們可以使用子例程來更高效地完成這個任務。假設所有的頭文件在工作目錄:
sub collect_recursive_includes {
# Unpack parameter from subroutine
my ($filename, $seen) = @_;
# Open the file to lexically scoped filehandle
# In your script, you'll probably have to transform $filename to correct path
open my $fh, "<", $filename or do {
# On failure: Print a warning, and return. I.e. go on with next include
warn "Can't open $filename: $!";
return;
};
# Loop through each line, recursing as needed
LINE: while(<$fh>) {
if (/^\s*#include\s+"([^"]+)"/) {
my $include = $1;
# you should probably normalize $include before testing if you've seen it
next LINE if $seen->{$include}; # skip seen includes
$seen->{$include} = 1;
collect_recursive_includes($include, $seen);
}
}
}
這個子程序記住它已經看到的文件,避免了遞歸有一次,每個文件只到過一次。
在頂層,你需要提供一個hashref作爲第二個參數,將控制所有的文件名作爲關鍵字子運行後:
my %seen = ($start_filename => 1);
collect_recursive_includes($start_filename, \%seen);
my @files = sort keys %seen;
# output @files, e.g. print "$_\n" for @files;
我在代碼中暗示的意見,你會probabably必須規範文件名。例如,考慮起始文件名爲./foo/bar/baz.h
,其指向qux.h
。那麼我們想要緩存的實際文件名是./foo/bar/qux.h
,而不是./qux.h
。 Cwd
模塊可以幫助您找到您當前的位置,並相對於絕對路徑進行轉換。 File::Spec
模塊更加複雜,但對平臺無關的文件名和路徑操作有很好的支持。
- 1. 如何使用SED/AWK/perl的
- 2. 使用SED或AWK
- 3. 遞歸使用SED
- 4. 如何用AWK或sed或Perl做這樣的替換?
- 5. 使用sed或awk更新一行
- 6. 如何使用變量來使用sed或awk進行搜索和替換?
- 7. 如何使用sed或awk去掉一組行或塊?
- 8. 如何使用awk或sed打印兩行相鄰的行?
- 9. 使用sed或awk進行文本提取
- 10. 使用SED或AWK進行碼型提取
- 11. 使用sed或awk進行xyz座標操作
- 12. 使用sed/awk/
- 13. 使用awk,sed
- 14. 如何使用遞歸縮進行?
- 15. 用AWK遞歸調用失敗?
- 16. 如何使用SQL進行遞歸調用?
- 17. 使用AWK或Perl轉置
- 18. 如何用awk進行多次傳遞?
- 19. 使用awk命令進行遞歸搜索
- 20. 如何使用perl像sed?
- 21. 加:用awk或者sed
- 22. 如何使用awk,perl或sed從LiveHTTPHeaders輸出中刪除響應?
- 23. sed或awk多行替換
- 24. 使用Sed/AWK/Perl從塊中提取第K行
- 25. 如何使用grep或awk或sed ..根據模式打印值?
- 26. 用sed或awk對輸出數據進行分組
- 27. 重命名使用awk或者sed
- 28. 使用修改文件awk或者sed
- 29. 使用SED或AWK替換文本零
- 30. 使用awk或sed排列列?
由於* ready.h *可能有自己的'#include',所以調用必須以遞歸方式**行爲,這意味着您可以在過程中簡單地堆疊數據。 – Rubens 2013-04-29 00:34:24
我不知道該怎麼做 – Exeter 2013-04-29 00:37:15
一個簡單的方法是維護一個列表,在其中添加你找到的條目,並循環考慮條件爲'while(list not empty);做$(與列表的最後一個元素的東西); $(在列表末尾插入新元素); ...; done'。但是,如果你試圖生成依賴樹,我不知道如何,但是爲了這個目的必須有一些已經創造出來的東西。 – Rubens 2013-04-29 00:52:25