2010-04-23 14 views
6

को प्रतिबिंबित करने के लिए, इसलिए मेरी वर्तमान दुविधा के दूसरे भाग के लिए, मेरे पास c:\file_list.txt में फ़ोल्डर की एक सूची है। मुझे लाइन नंबर के आधार पर उन्हें निकालने में सक्षम होना चाहिए (अच्छी तरह से, उन्हें कुछ मोड के साथ गूंजें) क्योंकि इस बैच स्क्रिप्ट को पुनरावर्तक मैक्रो प्रक्रिया द्वारा बुलाया जा रहा है। मैं रेखा संख्या को पैरामीटर के रूप में पास कर रहा हूं।विंडोज बैच फ़ाइल को एक विशिष्ट लाइन नंबर

@echo off 
setlocal enabledelayedexpansion 
set /a counter=0 
set /a %%a = "" 
for /f "usebackq delims=" %%a in (c:\file_list.txt) do (
    if "!counter!"=="%1" goto :printme & set /a counter+=1 
) 
:printme 
echo %%a 

जो मुझे %a का आउटपुट देता है। रवींद्र! इसलिए, मैंने !a! प्रतिबिंबित करने का प्रयास किया है (परिणाम: ECHO is off.); मैं गूंज की कोशिश की गए %a (परिणाम: एक)

मैं head.bat कोड मिला संशोधित करने के लिए किया जाएगा करने के लिए आसान बात समझ: बल्कि हर पंक्ति गूंज से छोड़कर Windows batch command(s) to read first line from text file
- मैं अभी पिछले गूंज होगी लाइन मिली जितना आसान हो सकता है उतना आसान नहीं। मैंने देखा है कि मेरा काउंटर कुछ कारणों से शून्य पर रहता है; मुझे आश्चर्य है कि set /a counter+=1 ऐसा कर रहा है जो मुझे लगता है कि यह कर रहा है।

+1

ध्यान दें कि 'for/f' खाली लाइनों को छोड़ देगा। यह कुछ मामलों में आपकी गिनती को फेंक देगा और शायद। – Joey

उत्तर

2

बह, यह मेरे स्वरूपण खा लिया।

@echo off 

setlocal enabledelayedexpansion 

set /a counter=0 
set %%a = "" 

for /f "usebackq delims=" %%a in (c:\file_list.txt) do (if "!counter!"=="%1" goto :printme & set /a counter+=1) 

:printme 

echo %%a% 
+0

आह, समझ गया। स्टार्टर्स सेट/काउंटर = 1 फिर %% के बराबर एक पर्यावरण चर सेट करें और इसे गूंजें - क्योंकि मुझे लगता है कि %% कोई कथन के बाहर मौजूद नहीं है। /f "usebackq delims =" %% a (c: \ file_list.txt) में करें (यदि "! काउंटर!" == "% 1" सेट लाइन = %% ए और गोटो: प्रिंटमे सेट/ए काउंटर + = 1) : प्रिंटमे प्रतिध्वनि% line% – Lee

12

मैं जानता हूँ कि यह एक पुराने सवाल है, लेकिन यहाँ एक समान मुद्दे के साथ किसी के लिए कुछ अतिरिक्त जानकारी है ...

ली, क्यों "%% एक" बाहर काम नहीं कर रहा पर अपने तर्क लूप के लिए सही है। % ए-जेड और% ए-जेड चर (बैच फ़ाइल के अंदर %% ए-जेड) लूप के लिए एक निर्माण है, और इसके बाहर मौजूद नहीं है।

मैं इस समस्या के वैकल्पिक समाधान की सिफारिश करना चाहता हूं जो सही रेखा संख्याओं से मेल खाता है (कोई खाली लाइन नहीं छोड़ी गई है) और देरी विस्तार, काउंटर या गोटो स्टेटमेंट की आवश्यकता नहीं है। निम्नलिखित कोड पर एक नज़र डालें:

@echo off 
for /f "tokens=1* delims=:" %%a in ('findstr /n .* "c:\file_list.txt"') do if "%%a"=="%1" set line=%%b 
echo.%line% 

यहां मुझे उपर्युक्त परिवर्तनों का कारण बताया गया है।

Some text on line 1 
Blah blah blah 
More text 

मैंने सोचा परिवर्तन था: मान लीजिए कि आप निम्न फ़ाइल सामग्री पड़ा करते हैं।: करें.अभियान (ग \ file_list.txt) ('findstr/n * "c: \ file_list.txt "')

  • 'findstr/एन। * "पथ \ FILENAME"' फ़ाइल हर पंक्ति (करने के लिए पढ़ता है और कहते हैं एक लाइन नंबर ('/एन') '। *' एक रेगुलर एक्सप्रेशन है किसी भी चरित्र के "0 या अधिक" से मिलान करना)। चूंकि प्रत्येक पंक्ति में अब शुरुआत में एक लाइन नंबर होगा (यहां तक ​​कि खाली वाले), लूप के लिए कोई लाइन नहीं छोड़ी जाएगी।

प्रत्येक पंक्ति पाश के लिए अंदर इस तरह दिखेगा:

1:Some text on line 1 
2:Blah blah blah 
3:More text 

इसके बाद, हम "टोकन = 1 * delims =:" का उपयोग लाइन नंबर और सामग्री को तोड़ने के लिए।

  • 'टोकन = 1 *' यह बाद सब कुछ करने के लिए पहले टोकन सीमांकक से पहले सब कुछ करने के लिए (%% एक में संग्रहीत), और दूसरा टोकन (%% ख में संग्रहीत) सेट ।
  • 'delims =:' सेट ":" स्ट्रिंग को तोड़ने के लिए उपयोग किए जाने वाले डेलीमीटर चरित्र के रूप में।

अब हम फ़ाइल के माध्यम से लूप के रूप में, %% एक वर्तमान लाइन नंबर वापस आ जाएगी और %% ख है कि रेखा की सामग्री वापस आ जाएगी।

अब सिर्फ़ % 1 पैरामीटर को %% एक (एक काउंटर चर के बजाय) की तुलना करने और %% ख का उपयोग वर्तमान पंक्ति सामग्री को संग्रहीत करने के लिए है: अगर "%% एक" == "% 1" सेट लाइन = %% बी

एक अतिरिक्त बोनस यह है कि 'enableelayedexpansion' अब आवश्यक नहीं है, क्योंकि उपरोक्त कोड लूप के बीच में काउंटर वैरिएबल पढ़ने को समाप्त करता है।

संपादित करें: '। गूंज% पंक्ति%' में बदल दिया 'गूंज% पंक्ति%'। यह "ईसीएचओ बंद है" के बजाय, अब रिक्त रेखाएं सही ढंग से प्रदर्शित करेगा। बदल दिया 'टाइप c: \ file_list.txt^| findstr/n। * 'to' findstr/n। * "c: \ file_list.txt" ', findstr कमांड पहले से ही फ़ाइलों को सीधे पढ़ सकता है।

जेब, मुझे लगता है कि मैंने सभी विशेष चरित्र मुद्दों को हल किया है। इस एक शॉट दे दो:

for /f "tokens=*" %%a in ('findstr /n .* "c:\file_list.txt"') do (
    set "FullLine=%%a" 
    for /f "tokens=1* delims=:" %%b in ("%%a") do (
    setlocal enabledelayedexpansion 
    set "LineData=!FullLine:*:=!" 
    if "%%b" equ "%1" echo(!LineData! 
    endlocal 
) 
) 
+0

मैंने इसका परीक्षण किया, लेकिन यह मेरी फ़ाइल के साथ विफल रहता है। सबसे पहले मैंने इसे ':::: कॉलन' के साथ करने की कोशिश की (सभी कोलों को हटा दिया गया है) और फिर मैंने इसे \ \ .. \ .. \ .. \ windows \ system32 \ calc.exe' के साथ परीक्षण किया, लेकिन यह नहीं करता इसे प्रिंट करें :-) – jeb

+0

अहह ... सुनिश्चित नहीं है कि calc.exe कोई काम क्यों नहीं करता है (ऐसा लगता है कि यह मेरे लिए काम करता है), लेकिन आप निश्चित रूप से मुझे कॉलन पर गिर गए सभी को मिला। मुझे उस विधि पर पुनर्विचार करना होगा। मैं 'findstr' के बजाय' find/n/v "" 'का उपयोग करूंगा, लेकिन फिर मैं एक ही समस्या के साथ समाप्त हो जाऊंगा: ']]]] ब्रैकेट' और '[[[[ब्रैकेट' दोनों बस के रूप में दिखाई देंगे 'Bracket'। उन delimiters को तोड़ने से बचने के लिए एक बहुत ही आसान तरीका प्रतीत नहीं होता है। –

+0

मुझे लगता है कि "अधिक + लाइन नम्बर" का उपयोग करने का आपका तरीका यह करने का एकमात्र विश्वसनीय तरीका हो सकता है ([link] (http://stackoverflow.com/questions/6409869/echo-the-nth-line -से-ए-पाठ-फ़ाइल-जहां-एन-है एक कमांड लाइन तर्क/13080820 # 13080820))। मुझे अब कुछ पोस्ट संपादित करना पड़ सकता है:/ –

1

आप इस प्रकार का बैच समारोह का उपयोग कर सकते हैं:

@ECHO OFF 
CALL :ReadNthLine "%~nx0" 10 
PAUSE >NUL 
GOTO :EOF 

:ReadNthLine File nLine 
FOR /F "tokens=1* delims=]" %%A IN ('^<"%~1" FIND /N /V "" ^| FINDSTR /B /C:"[%2]"') DO ECHO.%%B 
GOTO :EOF 

A line containing special shell characters:() <> %! ^| "& 

आउटपुट

विशेष खोल वर्ण युक्त लाइन:() <>%!^| "&

अमान्य लाइन नंबर

ऊपर समारोह भी खाली लाइनों या विशेष वर्ण युक्त लाइनों मुद्रित कर सकते हैं, और इस ज्यादातर मामलों के लिए पर्याप्त है।हालांकि, ताकि इस समारोह के लिए अमान्य लाइन नंबर संभाल करने में, इस तरह कार्य करने के लिए त्रुटि जाँच कोड जोड़ें:

:ReadNthLine File nLine 
FOR /F %%A IN ('^<"%~1" FIND /C /V ""') DO IF %2 GTR %%A (ECHO Error: No such line %2. 1>&2 & EXIT /b 1) 
FOR /F "tokens=1* delims=]" %%A IN ('^<"%~1" FIND /N /V "" ^| FINDSTR /B /C:"[%2]"') DO ECHO.%%B 
EXIT /b 

ReadNthLine2

  • विशेष वर्ण - मुद्रित

  • खाली रेखा - मुद्रित

  • गैर-मौजूदा रेखा - एक त्रुटि संदेश दिखाया गया

0

लाइन स्ट्रिंग्स w/o लाइन नंबर उपसर्ग (या यदि आप चाहते हैं) निकालने के लिए एक चाल है और सभी फाइल लाइनों पर बैच पुनरावृत्तियों ("के लिए/एफ" प्लस गिनती) का उपयोग करने की आवश्यकता है ।

ऐसा करने के लिए आपको /B /C:"<N1>:" /C:"<N2>:" ... /C:"<NX>:" तर्कों के माध्यम से पाइपलाइन में दूसरे findstr.exe द्वारा पाइपलाइन और बैकफिल्टर लाइनों में हमेशा find/find के साथ findstr.exe का उपयोग करना होगा।

यहाँ

print_file_string.bat स्क्रिप्ट मैं पाठ और बाइनरी फ़ाइलें पार्स करने के लिए उपयोग कर रहा हूँ:

@echo off 

rem Description: 
rem Script for string lines extraction from a text/binary file by findstr 
rem utility pattern and/or line number. 

rem Command arguments: 
rem %1 - Optional flags: 
rem  -n - prints line number prefix "<N>:" for each found string from file. 
rem   By default, the line number prefix does not print. 
rem  -f1 - filter by line numbers for strings after %4..%N filter pattern. 
rem   By default, filters by line numbers from the file. 
rem  -pe - treats input file as a Portable Executable file 
rem   (the strings.exe must exist). 
rem   By default, the file treated as a text file. 
rem %1 - Path to a directory with a file to extract. 
rem %2 - Relative path to a text/binary file with strings. 
rem %3 - Set of line numbers separated by : character to print strings of. 
rem  These line numbers by default are line numbers of strings from the 
rem  file, not from filtered output. If you want to point line numbers 
rem  after %4..%N filter pattern, then you must use -f1 flag. 
rem  If empty, then treated as "all strings". 
rem %4..%N - Arguments for findstr command line in first filter. 
rem  If empty, then treated as /R /C:".*", which means "any string". 

rem CAUTION: 
rem DO NOT use /N flag in %4..%N arguments, instead use script -n flag to 
rem print strings w/ line number prefix. 

rem Examples: 
rem 1. call print_file_string.bat -n . example.txt 1:20:10:30 /R /C:".*" 
rem Prints 1, 10, 20, 30 lines of the example.txt file sorted by line number 
rem and prints them w/ line number prefix: 
rem 
rem 2. call print_file_string.bat . example.txt 100 /R /C:".*" 
rem Prints 100'th string of example.txt file and prints it w/o line number 
rem prefix. 
rem 
rem 3. call print_file_string.bat -pe c:\Application res.dll "" /B /C:"VERSION=" 
rem Prints all strings from the c:\Application\res.dll binary file, where 
rem strings beginning by the "VERSION=" string and prints them w/o line number 
rem prefix. 
rem 
rem 4. call print_file_string.bat -pe c:\Application res.dll 1:20:10:30 /R /C:".*" 
rem Prints 1, 10, 20, 30 lines of string resources from the 
rem c:\Application\res.dll binary file, where strings beginning by the 
rem "VERSION=" string and prints them w/o line number prefix. 

setlocal EnableDelayedExpansion 

set "?~dp0=%~dp0" 
set "?~nx0=%~nx0" 

rem script flags 
set FLAG_PRINT_LINE_NUMBER_PREFIX=0 
set FLAG_F1_LINE_NUMBER_FILTER=0 
set FLAG_FILE_FORMAT_PE=0 

rem flags 
set "FLAGS=" 

:FLAGS_LOOP 

rem flags always at first 
set "FLAG=%~1" 

if not "%FLAG%" == ""^
if not "%FLAG:~0,1%" == "-" set "FLAG=" 

if not "%FLAG%" == "" (
    if "%FLAG%" == "-n" set FLAG_PRINT_LINE_NUMBER_PREFIX=1 
    if "%FLAG%" == "-f1" set FLAG_F1_LINE_NUMBER_FILTER=1 
    if "%FLAG%" == "-pe" set FLAG_FILE_FORMAT_PE=1 
    shift 

    rem read until no flags 
    goto FLAGS_LOOP 
) 

set "DIR_PATH=%~dpf1" 
set "FILE_PATH=%~2" 

set "FILE_PATH_PREFIX=" 
if not "%DIR_PATH%" == "" set "FILE_PATH_PREFIX=%DIR_PATH%\" 

if not "%FILE_PATH_PREFIX%" == ""^
if not exist "%FILE_PATH_PREFIX%" (
    echo.%?~nx0%: error: Directory path does not exist: "%FILE_PATH_PREFIX%" 
    exit /b 1 
) >&2 

if "%FILE_PATH%" == "" (
    echo.%?~nx0%: error: File path does not set. 
    exit /b 2 
) >&2 

if not exist "%FILE_PATH_PREFIX%%FILE_PATH%" (
    echo.%?~nx0%: error: File path does not exist: "%FILE_PATH_PREFIX%%FILE_PATH%" 
    exit /b 3 
) >&2 

set "LINE_NUMBERS=%~3" 

set "FINDSTR_LINES_FILTER_CMD_LINE=" 
if "%LINE_NUMBERS%" == "" goto FINDSTR_LINES_FILTER_END 

set LINE_NUMBER_INDEX=1 
:FINDSTR_LINES_FILTER_LOOP 
set "LINE_NUMBER=" 
for /F "tokens=%LINE_NUMBER_INDEX% delims=:" %%i in ("%LINE_NUMBERS%") do set "LINE_NUMBER=%%i" 
if "%LINE_NUMBER%" == "" goto FINDSTR_LINES_FILTER_END 

set FINDSTR_LINES_FILTER_CMD_LINE=!FINDSTR_LINES_FILTER_CMD_LINE! /C:"!LINE_NUMBER!:" 
set /A LINE_NUMBER_INDEX+=1 
goto FINDSTR_LINES_FILTER_LOOP 

:FINDSTR_LINES_FILTER_END 

shift 
shift 
shift 

set "FINDSTR_FIRST_FILTER_CMD_LINE=" 

:FINDSTR_FIRST_FILTER_LOOP 
set ARG=%1 

if not "!ARG!" == "" (
    set FINDSTR_FIRST_FILTER_CMD_LINE=!FINDSTR_FIRST_FILTER_CMD_LINE! !ARG! 
    shift 
    goto FINDSTR_FIRST_FILTER_LOOP 
) 

if "!FINDSTR_FIRST_FILTER_CMD_LINE!" == "" set FINDSTR_FIRST_FILTER_CMD_LINE=/R /C:".*" 

set OUTPUT_HAS_NUMBER_PREFIX=0 

rem in case if /N at the end 
set "FINDSTR_FIRST_FILTER_CMD_LINE=!FINDSTR_FIRST_FILTER_CMD_LINE! " 

rem 1. add /N parameter to first filter if must print line prefixes and -f1 flag is not set. 
rem 2. flags prefixed output if must print line prefixes. 
if %FLAG_PRINT_LINE_NUMBER_PREFIX% NEQ 0 (
    if %FLAG_F1_LINE_NUMBER_FILTER% EQU 0 (
    if "!FINDSTR_FIRST_FILTER_CMD_LINE:/N =!" == "!FINDSTR_FIRST_FILTER_CMD_LINE!" (
     set "FINDSTR_FIRST_FILTER_CMD_LINE=/N !FINDSTR_FIRST_FILTER_CMD_LINE!" 
    ) 
) 
    set OUTPUT_HAS_NUMBER_PREFIX=1 
) 

rem 1. add /N parameter to first filter and flags prefixed output if lines filter is not empty and -f1 flag is not set. 
rem 2. add /B parameter to lines filter if lines filter is not empty 
if not "!FINDSTR_LINES_FILTER_CMD_LINE!" == "" (
    if %FLAG_F1_LINE_NUMBER_FILTER% EQU 0 (
    if "!FINDSTR_FIRST_FILTER_CMD_LINE:/N =!" == "!FINDSTR_FIRST_FILTER_CMD_LINE!" (
     set "FINDSTR_FIRST_FILTER_CMD_LINE=/N !FINDSTR_FIRST_FILTER_CMD_LINE!" 
     set OUTPUT_HAS_NUMBER_PREFIX=1 
    ) 
) 
    if "!FINDSTR_LINES_FILTER_CMD_LINE:/B =!" == "!FINDSTR_LINES_FILTER_CMD_LINE!" (
    set "FINDSTR_LINES_FILTER_CMD_LINE=/B !FINDSTR_LINES_FILTER_CMD_LINE!" 
) 
) 

rem 1. remove /N parameter from first filter if -f1 flag is set. 
rem 2. flags prefixed output if -f1 flag is set. 
if %FLAG_F1_LINE_NUMBER_FILTER% NEQ 0 (
    if not "!FINDSTR_FIRST_FILTER_CMD_LINE:/N =!" == "!FINDSTR_FIRST_FILTER_CMD_LINE!" (
    set "FINDSTR_FIRST_FILTER_CMD_LINE=!FINDSTR_FIRST_FILTER_CMD_LINE:/N =!" 
) 
    set OUTPUT_HAS_NUMBER_PREFIX=1 
) 

if "%TOOLS_PATH%" == "" set "TOOLS_PATH=%?~dp0%" 
rem set "TOOLS_PATH=%TOOLS_PATH:\=/%" 
if "%TOOLS_PATH:~-1%" == "\" set "TOOLS_PATH=%TOOLS_PATH:~0,-1%" 

if %FLAG_FILE_FORMAT_PE% EQU 0 (
    set CMD_LINE=type "%FILE_PATH_PREFIX%%FILE_PATH%" ^| findstr !FINDSTR_FIRST_FILTER_CMD_LINE! 
) else (
    rem add EULA acception into registry to avoid EULA acception GUI dialog 
    reg add HKCU\Software\Sysinternals\Strings /v EulaAccepted /t REG_DWORD /d 0x00000001 /f >nul 2>nul 

    rem @ for bug case workaround 
    set [email protected]"%TOOLS_PATH%\strings.exe" -q "%FILE_PATH_PREFIX%%FILE_PATH%" ^| findstr !FINDSTR_FIRST_FILTER_CMD_LINE! 
) 

if %FLAG_F1_LINE_NUMBER_FILTER% NEQ 0 set CMD_LINE=!CMD_LINE! ^| findstr /N /R /C:".*" 
if not "!FINDSTR_LINES_FILTER_CMD_LINE!" == "" set CMD_LINE=!CMD_LINE! ^| findstr !FINDSTR_LINES_FILTER_CMD_LINE! 

rem echo !CMD_LINE! >&2 
(
    endlocal 
    rem to avoid ! character truncation 
    setlocal DisableDelayedExpansion 
    if %OUTPUT_HAS_NUMBER_PREFIX% NEQ 0 (
    if %FLAG_PRINT_LINE_NUMBER_PREFIX% NEQ 0 (
     %CMD_LINE% 2>nul 
    ) else ( 
     for /F "usebackq eol= tokens=1,* delims=:" %%i in (`^(%CMD_LINE: | findstr = ^| findstr %^) 2^>nul`) do echo.%%j 
    ) 
) else (
    %CMD_LINE% 2>nul 
) 
) 

exit /b 0 

लाभ:

  • से सभी लाइनों पर "/ एफ के लिए" यात्रा तेज़ फ़ाइल।
  • & जैसे विशेष वर्णों के साथ काम करता है। % "` '? और यहां तक ​​कि! चरित्र (एक वास्तविक dll संसाधनों पर परीक्षण)।
  • dll और exe (https://technet.microsoft.com/en-us/sysinternals/strings.aspx से strings.exe डाउनलोड करने और स्क्रिप्ट के पास रख दिया)। उदाहरण के लिए की तरह पीई फ़ाइलों से संसाधन तार हैंडल ।, आप exe/dll फ़ाइल में builtin तार से संस्करण स्कीमा निकाल सकते हैं

ज्ञात समस्याएँ:

  • लाइन (रों) करके एक फिल्टर का उपयोग किया है या -f1 ध्वज सेट है, तो : अक्षर (दोहराया गया) एक स्ट्रिंग की शुरुआत से छंटनी की जाएगी।
  • findstr में आंतरिक स्ट्रिंग बफर की सीमा है - 8191 वर्ण (लाइन रिटर्न वर्ण टर्मिनेटर सहित)। ज्यादातर मामलों में इस संख्या से अधिक सभी तारों को शून्य लंबाई तक छोटा कर दिया जाएगा।

उदाहरण:

  1. कॉल print_file_string.bat -n। example.txt 1: 20: 10: 30/R /C:".* "

    पंक्ति संख्या द्वारा क्रमबद्ध example.txt फ़ाइल की 1, 10, 20, 30 पंक्तियां मुद्रित करती हैं और उन्हें w/line संख्या प्रिंट करती है उपसर्ग:

  2. कॉल print_file_string.bat। example.txt 100/R /C:".* "

    example.txt फ़ाइल की 100 वीं स्ट्रिंग मुद्रित करता है और इसे पंक्ति संख्या उपसर्ग प्रिंट करता है।

  3. कॉल print_file_string.bat पीई c: \ आवेदन res.dll ""/बी/सी: "संस्करण ="

    प्रिंटों ग से सभी स्ट्रिंग्स: \ Application \ res.dll बाइनरी फ़ाइल है, जहां स्ट्रिंग्स "VERSION =" स्ट्रिंग से शुरू होती हैं और उन्हें w/o पंक्ति संख्या उपसर्ग प्रिंट करती है।

  4. कॉल print_file_string.bat पीई c: \ आवेदन res.dll 1: 20: 10: 30/आर /C:".* "

    प्रिंटों 1, 10, 20, स्ट्रिंग संसाधनों का 30 लाइनों सी: \ Application \ res.dll बाइनरी फ़ाइल से, जहां "VERSION =" स्ट्रिंग से शुरू होने वाली स्ट्रिंग्स और उन्हें w/o लाइन नंबर उपसर्ग प्रिंट करता है।

संबंधित मुद्दे