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

byqmnocz  于 2022-11-18  发布在  Windows
关注(0)|答案(3)|浏览(210)

我在Windows 8.1上使用jq 1.6,遇到与此处报告的问题相同的问题https://github.com/stedolan/jq/issues/1644
jq . *.json这样简单的命令失败,错误如下:
Assert失败!
程序:jq.exe文件:src/main. c,第256行表达式:wargc ==参数c
此应用程序已请求运行时以异常方式终止它。有关详细信息,请与应用程序的支持团队联系。
有没有人对此有解决方案?在windows上对文件夹中的所有文件使用jq的正确方法是什么?

gzszwxb4

gzszwxb41#

这是一个奇怪的问题。
answered by peak一样,cmd.exe不扩展通配符,把这个工作留给程序去做。而且jq不处理通配符(问题列表,稍后会详细介绍)。
但这并不是此次失败的全部原因。
正如问题所指出的,源代码在Assert中失败: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运行时中的参数处理确实扩展了通配符(微软编译器运行时没有,但这并不重要,因为它也不会解决问题)。
这意味着argcargv(由GCC代码通过通配符扩展确定)将根据与通配符匹配的文件数包含信息,而wargcwargv(由MS代码通过不带通配符扩展确定)将不包含信息。
一个简单的探测方法是在尝试前面的命令时只有一个.json文件。Assert不会失败,但jq会失败,因为它不处理通配符。

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

那么,如何处理它呢?在不修改jq的源代码的情况下,你最好的选择是连接文件列表并将其传递给jqReferences在peak的答案和你的评论中应该处理这个问题。
但是请记住,在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的命令行(Windows对命令行的限制)。

xtupzzrd

xtupzzrd2#

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/

nxowjjhe

nxowjjhe3#

MC ND给出了一个惊人的解释why this happens
但是,如果您只是想让它工作,我建议使用Windows Subsystem for Linux (WSL)Git Bash。这两种方法都在初始设置后处理通配符扩展。

  • 投资回报率非常高,因为无论何时您在使用cmd时遇到问题,都可以直接跳到bash并继续操作。*

相关问题