【问题标题】:Using wildcard for files with jq on Windows在 Windows 上对带有 jq 的文件使用通配符
【发布时间】:2018-11-20 07:02:52
【问题描述】:

我在 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的正确方法是什么?

【问题讨论】:

    标签: windows cmd jq


    【解决方案1】:

    这是一个奇怪的问题。

    正如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 的源代码的情况下,最好的选择是连接文件列表并将其传递给jqReferences 在 peak 的回答和您的评论中应该可以解决这个问题。

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

    @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 的命令行(命令行的窗口限制)。

    【讨论】:

    • 太棒了..如果我想使用多个文件夹,那么dir /b/s 也可以使用这个..
    • @Kamal, cmd 解析器在处理插入符号转义的命令行上执行了几次操作。试试"\"2018-05-06 11:12:13\" | capture(\"(?^^^^^^^<Y^^^^^^^>[0-9]+)\^")"
    • MD,感谢您的回复,实际上使用jq 的-f 选项我没有遇到这个问题(这就是我删除评论的原因)。我尝试了您共享的 cmd,它确实提供了预期的输出,但也在该输出之前打印了此错误File Not Found。你能解释一下确切的 6 个额外插入符号的原因吗?
    • @Kamal,一些插入符号逃脱了尖括号,有些则逃脱了转义符本身。每次解析该行时,都会使用一些插入符号作为转义字符。找到该行时会对其进行解析,但由于它包含一个管道,因此会启动一个单独的 cmd 实例来处理每一侧,然后右侧的 cmd 会再次对其进行解析。我们有^^^^^^^<。第一次解析后,我们有^^^<。在第二次解析^< 之后,即^<
    • 使用简单的 powershell 技巧:powershell jq . (get-item *.json)
    【解决方案2】:

    正如https://en.wikibooks.org/wiki/Windows_Batch_Scripting所解释的那样

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

    因此,假设您不能一次只处理一个文件,那么您要么必须 显式创建文件列表,或使用不同的 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/

    【讨论】:

    • 这个 [superuser.com/a/460648] 脚本有效,我可以在运行脚本后使用echo %expanded_list% 打印文件名,但是如何使用jq 使用该变量的输出?这不起作用jq empty %expanded_list%,但会给出类似parse error: Invalid numeric literal at line 2, column 0的错误
    • 当你运行jq empty FIRSTFILE 时会发生什么,其中FIRSTILE 是echo %expanded_list% 生成的第一个文件名?
    • 好的,我从您的评论中了解到问题所在,我的文件夹中有 .json 以外的文件,我更新了脚本以仅返回 .json 文件,现在它可以工作了。谢谢
    • 在包含太多文件的文件夹中使用时,出现The input line is too long.的错误
    猜你喜欢
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 2019-10-14
    • 2019-03-30
    • 1970-01-01
    • 2015-02-11
    • 2022-01-20
    • 2013-07-30
    相关资源
    最近更新 更多