命令行環境下簡單實用的工具——重定向&管道


如果你對管道和重定向應用自如了,無需繼續往下看。本文雖然以windows上cmd命令行環境演示,但同樣適用於Unix/Linux等平台。

引言

關於管道和重定向,最初是在劉汝佳的《算法競賽入門經典》上看到的,也是從那時開始用gcc(MinGW) & notepad++(在此之前,Linux上用的是Eclipse+CDT,windows上是VC)。一般操作系統的命令行環境下都提供了管道和重定向工具,看了劉汝佳的書才知道用txt代替鍵盤作輸入、測試是多么的方便!回想起每次點完GO之后一個數字一個數字的按鍵盤(而且筆記本鍵盤的數字鍵按起來沒有獨立鍵盤的數字區按起來那么爽)還不時按錯的痛苦經歷,決定今日將這一強大的工具與大家分享。

從A+B說起

練過OJ的同學可能對此深有體會(沒練過沒有關系),你的程序可能要先讀10個輸入(或者更多),才出結果;而你有很難保證這個程序一次編譯就是對的,每次修改后都要重新輸入這一堆數(還時不時的輸錯),實在讓人難以忍受!劉的書中說了兩種方法:

一.利用C標准庫提供的“重定向函數”freopen("input.txt",  "r", stdin);這種方法適合用在IDE上,添加一行代碼,再准備一個文本文件,你不用單獨打開一個cmd窗口,也能夠讓input.txt的文本帶你的所有鍵盤輸入。缺點就是你要在提交之時將這句代碼注釋掉(或者刪掉);相信不少同學在提交的時候因為忘了注釋這句而WA的。(在有的IDE上找源代碼文件所在目錄也不是很方便。)
下面就以經典的A+B問題為例。如下是A+B問題的一個解法,其中input.txt是事先已經准備好的測試數據,並且和這個代碼文件放在同一目錄下(VC上是這樣,有的IDE可能要和.exe放到同一目錄):

#include <stdio.h>

int main()
{
    int a,b;
    freopen("input.txt",  "r", stdin); 
    while( scanf("%d%d", &a, &b) == 2 )
    {
        printf( "%d\n", a+b );
    }
    return 0;
}

二.命令行環境下的————重定向。后面重點介紹
使用重定向的代碼不需要做任何手腳(假設保存為D:\OJ\aplusb.c):

#include <stdio.h>

int main()
{
    int a,b;
    while( scanf("%d%d", &a, &b) == 2 )
    {
        printf( "%d\n", a+b );
    }
    return 0;
}

下面就以編譯、測試位於D:\OJ目錄下的aplusb.c的步驟為例:

  1. (要使用重定向你必須)先打開一個cmd窗口,並讓cmd窗口的當前目錄為D:\OJ。
    win7上只需打開D:\OJ文件夾,按住SHIFT鍵,在窗口的空白處右擊鼠標,點“在此處打開窗口”即可。


    win xp上稍顯麻煩,
    step1. WinKey+R彈出運行窗口,鍵入“cmd”回車,
           彈出的cmd窗口顯示當前目錄是C:\Document and Setting\xxx(win7則是C:\Users\xxx);
    step2. 再鍵入“D:”回車,跳轉到D盤;
    step3. 再用cd命令跳轉到當前exe所在目錄(如果目錄名較長,可以從資源管理器的路徑欄上copy)。
    win7上當然也可以這么做,如下:
  2. 編譯aplusb.c
    假設你已經設置好了環境變量(如果你還沒有安裝配置命令行工具,點擊這里
    gcc aplusb.c 
    將會有a.exe生成(如果想以其他名稱輸出加上-o選項,如gcc -o OutName.exe aplusb.c);
  3. 測試a.exe
    假設你已經准備好了一份測試數據,並以input.txt保存在相同目錄(D:\OJ)下(如果沒有,創建一個),則可以:
    a.exe < input.txt
    程序a.exe將會直接運行,並且以input.txt為輸入;
    這里的<符號叫重定向輸入符(它右邊的文件將替換左邊程序或命令的標准輸入(cmd窗口輸入))
    如input.txt內容如下:
    1 2 
    3 4
    5 6
    7 8
    9 10
    100 200
    200 400
    400 800
    20000 30000
    5000000 6000000
    70000000 80000000
    運行gcc和a.exe后:

升級

A+B問題太簡單?現在換一個問題:
統計問題
一組整數,統計最大值、最小值、平均值
輸入
第一行一個32位整數n表示測試數據個數,接下來的n行每行一個非負32位整數
輸出
一行,最小值、最大值、平均值,空格分開
這個問題也比較簡單;之所以舉這個例子,只是為了突出重定向和管道的重要作用。
相信只要學過一點編程的都能立刻寫出來:
(這段程序里有個小錯誤,稍后現形)
保存為D:\OJ\Perls\sovle2.cpp
這里也有一份測試數據input.txt:
10
20
30
40
50
60
70
80
90
編譯:
gcc solve2.cpp -o solve.exe
測試:
solve.exe < input.txt

結果正確!

隨機數生成器

你可能對上面的一組測試數據不夠滿意,太少,太小,太弱?
下面寫一個能夠生成滿足題目輸入格式的隨機數生成器:

保存為rand_gen.c
該程序讀入n,輸出n及n個隨機數(正如題目輸入格式)。
編譯:
gcc rand_gen.c -o randgen.exe
運行:

這時你可使用重定向輸出符(它右邊的文件將替換標准輸出(cmd窗口輸出)):
randgen.exe > rand_data.txt
再用重定向輸入進行測試:
solve.exe < rand_data.txt

管道

在已經有randgen.exe的情況下,使用管道更加方便:
echo 10 | randgen.exe

echo是回顯程序,echo 10將會輸出10
“|”是管道符號,它將會把左邊的程序(或命令)的輸出重定向到右邊程序(或命令)的輸入.
這里的效果和前面手工輸入10是一樣的。
管道可以連接使用;所以,我們可以這樣:
echo 10 | randgen | solve
(.exe可以不用輸入)
過程是這樣的:
echo 10 ==10==> randgen.exe ==(臨時數據)===> solve.exe -> 屏幕輸出

這次測試出現了問題,最小值和平均值竟然都是負數!
查看一下代碼發現這里有兩個問題:
i.無符號整數應該用unsigned int;
ii.sum溢出,應該用double;
更正:
保存為final_solve.c
再次編譯測試:


附錄

windows官方參考使用命令重定向操作符:

http://technet.microsoft.com/zh-cn/library/cc772622(WS.10).aspx
Unix/Linux平台,參考文章:

http://man.chinaunix.net/linux/mandrake/101/zh_cn/Command-Line.html/shell-pipes.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM