[英]Why won't my program accept the piped output of another program properly?
我有一個用3個.c文件編譯的C程序。 本質上,該程序根據我在主菜單中定義的x和y大小輸入,將正方形輸出到標准輸出。 相關代碼如下:
void rush(int x, int y);
int main(void)
{
rush(3, 3);
return (0);
}
運行main的可執行文件,如下所示:
./a.out
給出以下內容:
o-o
| |
o-o
並將傳遞給rush函數的參數更改為(5,5)將產生以下結果:
o---o
| |
| |
| |
o---o
你明白了。 每行由\\ n分隔,這允許函數打印正確的下一行。 我還有另一個測試程序,它是一個簡單的編譯主程序,可以像我想要的那樣簡單地打印ARGC的值,以測試這種輸入將產生什么管道的行為。 第二個主程序是這樣的:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("argc value is: %d\n", argc);
return (0);
}
運行以下命令:
./a.out | ./test
我得到以下輸出:
argc value is: 1
最初對我來說這沒有意義,但后來我想起來是因為某些命令需要xargs才能正確接受來自stdin的輸入。 在主輸入中使用xargs(5,5)作為輸入:
./a.out | xargs ./test
導致:
argc value is: 9
因此,我有兩個問題。 有沒有一種方法不需要xargs,並且可以在c文件本身中完成? 知道測試文件的輸入后,為什么argc == 9? 程序如何分離出該格式的字符串並確定要放入數組的內容?
這會很長,所以請抓住您最喜歡的飲料。 休息后不要只跳到答案。
首先,檢查提供給程序的命令行參數args.c :
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
printf("argc = %d\n", argc);
for (i = 0; i < argc; i++)
printf("argv[%d] = \"%s\"\n", i, argv[i]);
return EXIT_SUCCESS;
}
使用您喜歡的C編譯器進行編譯; 我使用gcc:
gcc -Wall -O2 args.c -o args
如果你說
./args one two
它會輸出
argc = 3
argv[0] = "./args"
argv[1] = "one"
argv[2] = "two"
所有Unix都具有命令行實用程序或shell內置的printf
,其工作方式與C printf()
標准庫函數非常相似。 我們可以舉個例子
printf 'Hello, world!\nSecond line\nThird line\n'
我們會看到
Hello, world!
Second line
Third line
現在,如果我們用管道將兩者連接起來,
printf 'Hello, world!\nSecond line\nThird line\n' | ./args
我們得到
argc = 1
argv[0] = "./args"
因為./args
沒有參數,並且上面的args.c完全忽略了標准輸入。
xargs
實用程序命令讀取輸入,然后將其自身的命令行參數作為命令執行,並將其讀取的輸入添加為附加參數。 它也是高度可配置的。 如果你跑
printf 'Hello, world!\nSecond line\nThird line\n' | xargs ./args
你會得到
argc = 7
argv[0] = "./args"
argv[1] = "Hello,"
argv[2] = "world!"
argv[3] = "Second"
argv[4] = "line"
argv[5] = "Third"
argv[6] = "line"
因為xargs將輸入中的每個標記(由空格分隔)轉換為命令行參數。 如果我們告訴xargs使用-d SEPARATOR
選項,並以換行符作為分隔符,將每條輸入行變成一個單獨的參數:
printf 'Hello, world!\nSecond line\nThird line\n' | xargs -d '\n' ./args
我們得到
argc = 4
argv[0] = "./args"
argv[1] = "Hello, world!"
argv[2] = "Second line"
argv[3] = "Third line"
如果我們告訴xargs每個執行的命令最多添加兩個參數,方法是添加-n 2
選項,
printf 'Hello, world!\nSecond line\nThird line\n' | xargs -d '\n' -n 2 ./args
我們會得到
argc = 3
argv[0] = "./args"
argv[1] = "Hello, world!"
argv[2] = "Second line"
argc = 2
argv[0] = "./args"
argv[1] = "Third line"
此輸出意味着我們的./args
實際上執行了兩次。 首先是有效的./args 'Hello, world!' 'Second line'
./args 'Hello, world!' 'Second line'
,第二個是./args 'Third line'
。
xargs的另一個重要選項是-r
,它告訴它在沒有任何其他參數的情況下不要運行命令:
true | xargs -r ./args
不會輸出任何內容,因為xargs看不到任何輸入,並且-r
選項告訴它如果沒有其他參數,則不要運行我們的args程序。
在處理文件名或路徑時, -0
(零號)選項告訴xargs輸入分隔符是nul字符\\0
,它在C中分隔字符串。 如果我們在xargs的輸入中使用該參數,則即使帶有換行符的字符串等也將正確地拆分為參數。 例如:
printf 'One thing\non two lines\0Second thing' | xargs -0 ./args
將輸出
argc = 3
argv[0] = "./args"
argv[1] = "One thing
on two lines"
argv[2] = "Second thing"
如果以一種可靠的方式處理文件名或路徑,這正是人們想要的。
有沒有一種方法不需要xargs,並且可以在c文件本身中完成?
當然:只需閱讀標准輸入即可。 幾乎可以肯定,xargs在所有Unixy系統上都是用C編寫的。
[xargs]如何分離出該格式的字符串並決定將哪些內容放入數組中?
簡短的答案是,它取決於所使用的選項,因為xargs是一個非常強大的小工具。
完整的答案是,查看源代碼。 GNU xargs(findutils的一部分)的源在這里 ,而FreeBSD版本的源在這里 。
代碼答案取決於是否可以使用POSIX.1,尤其是getline()
或getdelim()
。 如果您有一個單字符分隔符(可以是任何單字節字符,甚至是nul),則可以使用getdelim()
作為單獨的字符串從輸入中獲取每個“參數”。 這是我要做的,但是它不是unix ,而是posix解決方案。 (現在,如果您擁有一台維護良好的Unixy計算機,則幾乎可以肯定的是,其C庫內置了POSIX.1支持。)
為什么argc == 9?
如果我們使用printf 'o---o\\n| |\\n| |\\n| |\\no---o\\n'
復制您的輸入 printf 'o---o\\n| |\\n| |\\n| |\\no---o\\n'
printf 'o---o\\n| |\\n| |\\n| |\\no---o\\n'
並將其通過管道傳遞給xargs ./args
,輸出與預期的一樣,
argc = 9
argv[0] = "./args"
argv[1] = "o---o"
argv[2] = "|"
argv[3] = "|"
argv[4] = "|"
argv[5] = "|"
argv[6] = "|"
argv[7] = "|"
argv[8] = "o---o"
也就是說,您的ascii藝術的每個部分都在空格處分隔,並作為命令行參數提供。 如果我們將其通過管道傳遞到xargs -d '\\n' ./args
,則輸出為
argc = 6
argv[0] = "./args"
argv[1] = "o---o"
argv[2] = "| |"
argv[3] = "| |"
argv[4] = "| |"
argv[5] = "o---o"
如果您為自己編寫了該初始args.c程序,則可能可以通過探索自己找到問題的答案。 這就是使編程如此強大的原因:您可以編寫工具來幫助您理解希望解決的問題。 應用Unix哲學和KISS原理意味着這些工具通常也很容易編寫。 只需將它們寫得很好就可以了,因此您可以信任它們的結果,而不必經常重寫它們。
發生這種情況是因為xargs接受整個輸入(所有行,而不僅僅是一行),並用空格字符將其分割。 因此,您的測試代碼得到的參數是(您可以自己打印它們以進行調試):
如果您打算從stdin讀取而不是解析參數,請使用cin >> string_variable
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.