为什么我的脚本无法正常运行?

为什么我的脚本无法正常运行?

我正在尝试./script.sh像这样使用我的:

./compile.sh -n NAME_ALBUM -f 000 000 000 000 -l 000 000 000 000
  • 在哪里-n是 ALBUM_NAME 并对应于正在保存的输出文件名
  • 在哪里-F含义 First 是播放列表中首先出现的视频文件名列表
  • 在哪里-l含义 Last 是播放列表中最后一个视频文件名的列表

然后播放列表被馈送到ffmpeg...

#!/bin/sh

# usage: ./compile.sh -n NAME_ALBUM -f 000 000 000 000 -l 000 000 000 000
# OPTION -n is for NAME, video file NAME.
# OPTION -f is for FIRST, video numbers to come FIRST in playlist.
# OPTION -l is for LAST, video numbers to come LAST in playlist.
# NOTE: mp4 videos are numbered as 001.mp4, 002.mp4, 003.mp4
# NOTE: if no videoss are mentioned in -f or -l then it will be ignored by default.
# Q1: possible to use more than (4) videos in -f or -l ?

while getopts ":n:f:l:" options; do

  case "${options}" in
    n)
      $1=${OPTARG}
      ;;
    f)
      $2=${OPTARG}
      ;;
    l)
      $3=${OPTARG}
      ;;
    h)
      echo "Help contents:
            ./compile.sh -n NAME_ALBUM -f 000 000 000 000 -l 000 000 000 000"
      ;;
    :) # not sure what this is
      echo "Error: -${OPTARG} requires an argument." #not sure what this is
      exit_abnormal
      ;;
    *) # or what this ones for
      exit_abnormal
      ;;
  esac
done
exit 0

# mp4 video file name that gets compiled
COMPILED=$1_$(date +'%Y-%m-%d_%H:%M:%S')

# video playlist fed to ffmpeg
VIDEO_LIST=list_$(date +'%Y-%m-%d_%H:%M:%S').txt


find *.mp4 | sed 's:\ :\\\ :g' | sed 's/^/file /' | sort -R  > $VIDEO_LIST; (printf 'g?%s?m0\n' $2 ; printf 'wq\n') | ed -s $VIDEO_LIST; ( printf 'g?%s?m$\n' $3 | tac; echo 'wq'; ) | ed -s $VIDEO_LIST; ffmpeg -f concat -i $VIDEO_LIST -c:v libx264 -crf 12 -preset slow -c:a copy $COMPILED.mp4

到底是什么阻止了我的脚本工作?

问:这个脚本到底做了什么?

它为 ffmpeg 创建所需的播放列表,其中包含该目录中的视频(最好将视频重命名为 001.mp4、002.mp4 等,这使得附加的“第一个/最后一个”选项更易于使用)并随机随机播放所有视频播放列表中的视频并将其交给 ffmpeg 编译为一个视频。附加选项:如果需要使某些视频在播放列表中排在第一位或/和最后一位,只需输入数字即可。执行脚本时将文件名写入命令行。

答案1

除了 John1024 评论的内容之外,类似的参数-f file1 file2 file3实际上会被读取为-f file1:只有第一个值被读入脚本,其他值都会丢失。你的-l论点也是如此。

您可以做的是指定一个字符串,它实际上是一个值列表(注意值周围的单引号):

./compile.sh -n NAME_ALBUM -f 'file1 file2 file3' -l 'file7 file8 file9'

这样,您将以:

  • 您的选项的价值-f是“ file1 file2 file3
  • 您的选项的价值-l是“ file7 file8 file9

您“只需”拆分它们即可获取文件名。像这样的结构应该会启发你:

f='file1 file2 file3'; for fileName in $f; do echo "$fileName"; done

在评论中提出问题后编辑:

使用过程中需要报价吗?或者它们可以隐藏在脚本中吗?因为我已经想到了这一点,但我认为它们必须在脚本的命令行使用过程中使用,这不是我想要的。

这对我来说并不完全清楚,但我可以告诉你:

  • 'file1 file2 file3'(带引号)是单个字符串(带空格)并将其存储在变量中或将其作为参数传递(如-f <value>)是完全可行的
  • file1 file2 file3(不带引号)是 3 个不同的字符串(因为空格充当参数分隔符。-f <value>除非您使用像上面那样的 hack(即引号),否则您不能将 3 个值传递给构造中的单个参数

另外,$2 $3 $4 $5 as -f 和 $6 $7 $8 $9 as -l 怎么样?

混合getopts构造和$n参数最终会产生不可读的脚本。此外,该$n策略涉及恰好有 4 个值-f和 4 个值-l

我的建议仍然是为您的-f-l选项提供文件列表:'file1 file2 file3'并在脚本中剪切这些列表。

答案2

您可以用作|一行中的最后一个字符,并且该行将继续。

例如

foo | bar | wc

相当于

foo |
bar |
wc
  • 请注意,它将;像换行符一样分隔命令。

我缩进脚本的最后部分,在外部插入新行|;

最后一行看起来像

find *.mp4 |
 sed 's:\ :\\\ :g' |
 sed 's/^/file /' | 
 sort -R  > $VIDEO_LIST

 (printf 'g?%s?m0\n' $2 ; printf 'wq\n') |
 ed -s $VIDEO_LIST

 ( printf 'g?%s?m$\n' $3 | tac; echo 'wq'; ) |
 ed -s $VIDEO_LIST

 ffmpeg -f concat -i $VIDEO_LIST -c:v libx264 -crf 12 -preset slow -c:a copy $COMPILED.mp4
  • $2来自哪里$3?命令行 ?用于set alpha bravo charly? (其他答案解决了这一点)

  • 看起来像是'\n'第二个 sed 中缺少的内容。

  • 成为一名冒险家 将您的脚本提交给https://codereview.stackexchange.com/

相关内容