Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
686 views
in Technique[技术] by (71.8m points)

linux - Syntax error: "(" unexpected -- with !(*.sh) in bash script

I want to run a sh file:

#!/bin/bash
for f in !(*.sh); do
    ffmpeg -i "$f" -vf yadif=0:-1 -threads 0 -c:v libx264 -pix_fmt yuv420p 
        -r 29.97 -b:v 3000k -s 1280x720 -preset:v slow -profile:v Main 
        -level 3.1 -bf 2 -movflags faststart /mnt/media/out-mp4/"${f%.mxf}.mp4"
    rm $f
done

However, I get the following error:

2: task1.sh: Syntax error: "(" unexpected

If I try directly on the command line it works perfectly.

the path and permissions are already reviewed

Any idea what might be happening?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is not a "sh file" -- it's a bash script. If you run it with sh yourscript, it will not work (as extglobs, the shell feature you're trying to use, aren't supported in POSIX sh); it needs to be run only with bash yourscript, or with ./yourscript when starting with #!/bin/bash (as it does). Describing it as a "sh file" is thus misleading. Moreover, even with bash, the extended globbing feature needs to be turned on.


Your immediate issue is that !(*.sh) is not regular glob syntax; it's an extglob extension, not available by default. You may have a .bashrc or similar configuration file which enables this extension for interactive shells, but that won't apply to scripts. Run:

shopt -s extglob

...to enable these features.


Cleaned up, your script might look like:

#!/bin/bash

shopt -s extglob

# putting settings in an array allows unescaped newlines in definition
# also sorted to make it easier to find things.
settings=(
  -b:v 3000k
  -bf 2
  -c:v libx264
  -level 3.1
  -movflags faststart
  -pix_fmt yuv420p
  -preset:v slow
  -profile:v Main
  -r 29.97
  -s 1280x720
  -threads 0
  -vf yadif=0:-1
)

for f in !(*.sh); do
    ffmpeg "${settings[@]}" -i "$f" 
      /mnt/media/out-mp4/"${f%.mxf}.mp4" && rm -- "$f"
done

Note the following changes, above and beyond formatting:

  • shopt -s extglob is on its own line, before the glob is expanded.
  • The rm is only run if ffmpeg succeeds, because the separator between those commands is &&, rather than either ; or a bare newline.
  • The -- argument passed to rm tells it to treat all future arguments (in this case, the content of "$f") as a filename, even if it starts with a dash.
  • The "$f" argument to rm is inside double quotes.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...