首页 > 解决方案 > Powershell中的行继续中间字符串

问题描述

我正在尝试在具有两个相同捕获卡的系统上编写 FFmpeg 命令,因此我必须使用它们的“备用名称”,否则 FFmpeg 不明白我在调用哪一个。

唯一的问题是备用名称非常长,尤其是在通过 dshow 同时调用音频和视频时:

-i video="@device_pnp_\\?\usb#vid_07ca&pid_0570&mi_00#7&3886ab1a&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global":audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0E6F0DEF-2B29-4117-8D30-13F01160AC5B}"

我想在调用音频之前打破这个“字符串”中线以使其更具可读性,如下所示:

-i video="@device_pnp_\\?\usb#vid_07ca&pid_0570&mi_00#7&3886ab1a&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"`
:audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0E6F0DEF-2B29-4117-8D30-13F01160AC5B}"

但是反引号在这种情况下似乎不起作用,我猜是因为它与字符接壤?如果我在反引号之前加一个空格,它会破坏字符串并且 FFmpeg 错误:

    -i video="@device_pnp_\\?\usb#vid_07ca&pid_0570&mi_00#7&3886ab1a&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" `
:audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0E6F0DEF-2B29-4117-8D30-13F01160AC5B}"

无论如何在Powershell中将其拆分为多行?

编辑 - 全功能命令:

ffmpeg -y -hide_banner -thread_queue_size 9999 -indexmem 9999 -guess_layout_max 0 -f dshow -rtbufsize 2147.48M `
-video_size 1920x1080 -framerate 60 `
-i video="@device_pnp_\\?\usb#vid_07ca&pid_0570&mi_00#7&3886ab1a&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global":audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0E6F0DEF-2B29-4117-8D30-13F01160AC5B}" `
-thread_queue_size 9999 -indexmem 9999 -guess_layout_max 0 -f dshow -rtbufsize 2147.48M `
-video_size 1920x1080 -framerate 60 `
-i video="@device_pnp_\\?\usb#vid_07ca&pid_0570&mi_00#7&24df76f&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global":audio="@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0A494693-5F33-4304-88D7-394757E09648}" `
-map 0:0,0:1 -map 0:1 -map 1:0,1:1 -map 1:1 -c:v h264_nvenc -r 60 -rc-lookahead 120 -forced-idr 1 -strict_gop 1 `
-sc_threshold 0 -flags +cgop -force_key_frames "expr:gte(t,n_forced*2)" -preset: llhp -pix_fmt yuv420p -b:v 250M `
-minrate 250M -maxrate 250M -bufsize 250M -c:a aac -ar 44100 -b:a 384k -ac 2 -af "aresample=async=250" -vsync 1 `
-max_muxing_queue_size 9999 -f segment -segment_time 600 -segment_wrap 9 -reset_timestamps 1 `
-segment_format_options max_delay=0 C:\Users\Jordan\Videos\FFmpeg\FFmpeg%02d.ts

我的目标是打破我对视频/音频设备的要求,以更好地适应街区的其余部分。

标签: powershellsyntaxreadabilityline-continuation

解决方案


在 PowerShell中的字符串`内或字符串之间的行尾使用与在 Bash中使用for line continuation的工作方式不同,例如:"..."\

如果放置在一行的最后,While`确实会在 PowerShell 中启用续行:

  • 跨行"..."字符串中使用时,` 转义换行符,而不删除它,这实际上是一个no-op,因为 PowerShell 字符串文字中的换行符不需要转义。

  • 当您尝试在应形成单个参数的字符串之间使用时(将在单行上直接相邻放置的字符串,例如,video="...":audio="..."),` 有效地充当参数分隔符,因此您无法拆分应该这样就变成了一个字符串。[1]

简而言之:在 PowerShell中,

  • 只能在arguments之间使用换行符。

  • 为了将单个参数分布在多行中,您需要使用表达式( (...));允许表达式跨越多行而无需续行。


在您的情况下,一种选择是将字符串部分指定为数组的元素,稍后将这些元素连接起来形成单个字符串。

使用一个简化的例子;请注意该-join技术如何与使用换行符共存以`将命令分布在参数之间的多行

ffmpeg -framerate 60 `
  -i ((
    'video=@device_pnp_\\?\1', 
    'audio=@device_cm_2'
  ) -join ':') `
  -f dshow

这在执行时转换为以下单行:

ffmpeg -framerate 60 -i video=@device_pnp_\\?\1:audio=@device_cm_2 -f dshow

请注意,您最初的参数内部引用 ( video="...":audio="...")没有被使用,因为它通常不是必需的(尽管某些程序,例如msiexec,遗憾地需要它)。

PowerShell 会根据需要自动为外部程序使用双引号,即它们是否包含 PowerShell 认为不在嵌入式双引号内的空格。有关更多信息,请参阅此答案,包括何时可能出现问题。


另一种选择是预先构造(仅)长参数并通过变量引用它们:

$inputSpec = (
  'video=@device_pnp_\\?\1', 
  'audio=@device_cm_2'
) -join ':'

ffmpeg -framerate 60 -i $inputSpec -f dshow

为了通常将命令的参数分布在多行中而不必在参数之间`的行尾使用,请在前面构造一个数组中的参数,并使用splatting来传递它:

# Construct an array containing all arguments.
# Note: Each parameter (+ operand, if any) is placed on its own line
#       here for clarity, but you're free to choose as many or few 
#       lines desired.
$ffmpegArgs =
  '-y', 
  'hide_banner', 
  '-thread_queue_size', '9999', 
  '-indexmem', '9999', 
  '-guess_layout_max', '0', 
  '-f', 'dshow', 
  '-rtbufsize', '2147.48M',
  '-video_size', '1920x1080', 
  '-framerate', '60',
  '-i', ((
    'video=@device_pnp_\\?\usb#vid_07ca&pid_0570&mi_00#7&3886ab1a&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global',        
    'audio=@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{0E6F0DEF-2B29-4117-8D30-13F01160AC5B}'
  ) -join ':')

  # ...

# Pass the array via splatting - note the '@'
ffmpeg @ffmpegArgs

笔记:

  • Splatting 的主要用例是启用命令参数的编程构造,并且需要不同的语法,如图所示。

  • 这个 - 最终被拒绝- RFC 提案提出了新的语法,这将使具有常规参数语法的多行延续更容易,而无需`在每个内部行的末尾;被拒绝的决定就在这里


[1] 有关 PowerShell 如何解析复合标记的更多信息,请参阅此 GitHub 问题


推荐阅读