如何连接命令行的各个部分

时间:2016-03-10 17:21:44

标签: bash command-line

我遇到了问题:现有工具正在调用ffmpeg -i path to file -f wav -ar 16000 ...但它无法逃脱路径。 (它应该是ffmpeg -i path\ to\ file -f ...修复工具或它产生的路径并非易事。

所以我的想法是创建一个名为ffmpeg的小脚本,将它放在真正的ffmpeg之前的$ PATH上,并在修复它们之后转发参数。 "修复它们"意味着将${2}连接到${n-1},其中${n}是跟随路径的-f参数。

但是我怎么写这个循环? This answer循环遍历所有参数,我可能会检测到该循环中的-f参数,但是如何重新组合真正的ffmpeg进程的命令行呢?

2 个答案:

答案 0 :(得分:1)

你真的需要报告这是一个错误,这是一个令人尴尬的初学者的错误,并不难解决。

无论如何,这里有一个kludge:

#!/bin/bash
array=()

start="-i"
stop="-f"

fileArg=0
for param
do
  if [[ $fileArg = 1 ]]
  then
    if [[ $param = $stop ]]
    then
      fileArg=0
      array+=("${file% }" "$param")
    fi
    file+="$param "
  else
    [[ $param = $start ]] && fileArg=1
    array+=("$param")
    file=""
  fi
done

printf "Your broken tool provided these argument:\n"
printf "%q " "$@"
printf "\n\n"
printf "Tried to salvage it by turning it into:\n"
printf "%q " "${array[@]}"
printf "\n"
/path/to/real/ffmpeg "${array[@]}"

这里的示例输出:

$ ./ffmpeg  -i path to file -f wav -ar 16000
Your broken tool provided these argument:
-i path to file -f wav -ar 16000

Tried to salvage it by turning it into:
-i path\ to\ file -f wav -ar 16000

这并不适用于所有情况 - 没有好办法重新组合已拆分为shell字的文件名。这种方法可以打破连续的多个空格,全局,大括号扩展,引号,美元,反引号等。如果文件名中有不匹配的引号或括号,该工具很可能甚至无法调用ffmpeg(或此替换)。

作为一个很好的功能,如果该工具被修复,这个脚本将是一个无操作(假设文件名仍在-i和-f之间)

答案 1 :(得分:1)

如果您能够使用awksed或类似的东西将未引用的命令传递给函数,则可以修复引用或在路径为时将其转义总是在同样的两个选项中:

#!/bin/env bash
# quote_path.sh
# wraps quotes or escapes an unquoted path in a command

# takes command with unquoted path and wraps in quotes 
quoted_cmd()
{
    quoted=$(echo $cmd | awk '{ sub(/ -f/,"\" -f"); sub(/-i /,"-i \""); print }')
    # eval $quoted
    escape_cmd # comment out if using eval $quoted
}

# takes quoted_cmd() and escapes it (as an alternative to wrapping in quotes)
escape_cmd() 
{   
    escape=$(echo $quoted | awk 'BEGIN { FS="-i \"|\" -f" } ; { print $2 }')
    concat=$(echo $escape | sed 's! !\\\\ !g')
    cmdesc=$(echo $quoted | awk '{ sub(/".*" -f/," -f"); $2="-i '"${concat}"'"; print }')
    eval $cmdesc
}

cmd="$@"
quoted_cmd

因此,您可以将您的命令作为参数传递(作为字符串或变量):

$ ./quote_path.sh ffmpeg -i /path to file /path to file -f wav -ar 16000 "foobar" ...

作为 Etan Reisner ,其他人提到,它应该被报告为一个错误,同时它就是它...试一试!

更新:我能够稍微修改一下这个函数,以便在命令的另一部分有带引号的参数,包含其他斜杠等的情况下失败的可能性更小。该命令在将其作为参数传递(可选)时不应要求引用,并且将在命令中生成带引号或转义路径。调用该函数后,返回整个路径,并与命令的其余部分连接。

<强>结果:

ffmpeg -i "/path to file /path to file" -f wav -ar 16000 ... # quoted_cmd()
ffmpeg -i /path\ to\ file\ /path\ to\ file -f wav -ar 16000 ... # escape_cmd()
... 
ffmpeg version 2.5.3-tessus Copyright (c) 2000-2015 the FFmpeg developers
...