在Windows上使用通配符处理带有jq的文件

时间:2018-11-20 07:02:52

标签: windows cmd jq

我正在Windows 8.1上使用jq 1.6,并且遇到与此处报告的相同的问题 https://github.com/stedolan/jq/issues/1644

简单到jq . *.json的命令失败,并显示以下错误:

  

断言失败!

     

程序:jq.exe   文件:src / main.c,第256行   表达式:wargc == argc

     

此应用程序已请求运行时   以不寻常的方式终止它。请联系应用程序的   支持团队以获取更多信息。

有人对此有解决方案吗?在Windows文件夹中的所有文件中使用jq的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

这是一个奇怪的问题。

正如answered by peak一样,cmd.exe不会扩展通配符,而将这项工作留给了程序。并且jq不处理通配符(在问题列表中,稍后会有更多介绍)。

但这不是失败的全部原因。

问题在于,源代码在断言wargc == argc中失败。读取源代码时,在Windows jq中尝试使用

处理原始命令行
 wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);

尝试检索与argv[]argc等效的内容,但处理多字节参数。

由于cmd未扩展通配符,因此将存在三个参数(有问题的命令行)

jq  .  *.json
^^  ^  ^....^  
0   1  2      
argv[]wargv[]中都是

,因此argcwargc应该匹配。

然后,为什么它失败了?为什么argcwargc不同?

因为使用了GCC来编译程序。

不,问题不在于GCC本身。 “问题”是,GCC运行时中的参数处理确实扩展了通配符(Microsoft编译器运行时没有,但是没关系,因为它也不能解决问题)。

这意味着argcargv(由具有通配符扩展名的GCC代码确定)将包含根据与通配符匹配的文件数的信息,而wargcwargv (由没有通配符扩展的MS代码确定)不会。

一种简单的探测方法是尝试上一个命令时只有一个.json文件。断言不会失败,但是jq会以jq: error: Could not open file *.json: Invalid argument失败,因为它不处理通配符。

jq . test.json       As seen in argv   argc  = 3
jq . *.json          As seen in wargv  wargc = 3

那么,如何处理呢?不修改jq的源代码,最好的选择是串联文件列表并将其传递给jq。峰的答案和您的评论中的References应该可以解决问题。

但是请记住,在cmd和批处理文件中,命令行限制为8191个字符。如果不足以解决您的问题,您可以尝试使用类似的方法(是的,很多行,其中大多数是注释和命令用法)

@if (@this==@isBatch) @then /* ------------------------------------- batch code
@echo off
    setlocal enableextensions disabledelayedexpansion

    rem This is an hybrid batch/javascript file. The batch part will retrieve
    rem the required information and start the cscript engine to execute the 
    rem javascript part of this file.

    rem Retrieve a safe reference to current batch file 
    call :getCurrentFile thisFile fileName

    rem Arguments to current batch file are the command line to execute later
    rem Using an environment variable to avoid losing quotes when using the
    rem internal Wscript argumeng handling routines
    set [commandLine]=%*

    if not defined [commandLine] (
        echo(
        echo usage: command1 ^| "%fileName%" command2
        echo(
        echo where:
        echo     command1   is a command generating a set of lines that will be
        echo                concatenated to pass as arguments to command2
        echo(
        echo     command2   is the command to execute with all the lines from 
        echo                command1 as command line arguments
        echo(
        echo examples:
        echo(
        echo    dir /b ^| "%fileName%" cmd /c echo
        echo    dir /b *.json ^| "%fileName%" jq . 
        echo(
        goto :eof
    )

    rem Execute the javascript part of this script
    "%windir%\system32\cscript.exe" //nologo //e:JScript "%thisFile%" 
    goto :eof


:getCurrentFile fullPath fileName
    set "%~1=%~f0"
    set "%~2=%~nx0"
    goto :eof

------------------------------------------------------------- end of batch code
*/@end //------------------------------------------------------ javascript code

/*
    This script will read all lines from standard input and execute the 
    command stored by the batch code above into the [commandLine] environment 
    variable, passing as command lien arguments the concatenation of all lines 
    present in the standard input.
*/

var shell = WScript.CreateObject('WScript.Shell')
  , commandLine = shell.Environment("PROCESS").Item('[commandLine]')
  , stdIn = WScript.StdIn
  , stdOut = WScript.StdOut
  , stdErr = WScript.StdErr
  , line = ''
  , buffer = []
  ;
    // read the list of arguments from standard input
    while ( !stdIn.AtEndOfStream ){ 
        if ( 
            line = stdIn.ReadLine().replace(/"/g, '') 
        ) buffer.push( ' "' + line + '"' );
    };

    // concatenate all arguments 
    buffer = buffer.join('');

    // if we don't have a command line, output what we have contatenated 
    // but if we have a command line, execute it, get its output and show it
    // as it is possible that we are piping it to another process.

    if ( commandLine ){
        try {
            stdOut.WriteLine(
                shell.Exec( commandLine + buffer ).StdOut.ReadAll()
            );
        } catch ( e ){
            stdErr.WriteLine( 'ERROR: Command line exec failed when running:' );
            stdErr.WriteLine( '---------------------------------------------' );
            stdErr.WriteLine( commandLine + buffer );
            stdErr.WriteLine( '---------------------------------------------' );
        };
    } else {
        stdOut.WriteLine( buffer );
    };

将其另存为cmd文件(例如list2args.cmd)并按建议使用

dir /b *.json | list2args.cmd jq .

区别在于,在脚本部分内部进行串联并使用WScript.Shell.Exec方法启动进程,我们可以使用最大32KB(命令行的窗口限制)的命令行。

答案 1 :(得分:1)

https://en.wikibooks.org/wiki/Windows_Batch_Scripting

所述
  

“与某些其他操作系统的外壳不同,cmd.exe外壳不执行通配符扩展”

因此,假设您不能一次简单地处理一个文件,则要么必须 显式创建文件列表,或使用其他Shell。

有关更多详细信息和建议,请参阅 https://superuser.com/questions/460598/is-there-any-way-to-get-the-windows-cmd-shell-to-expand-wildcard-paths

,如果您使用的是Windows 10:

https://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/