命令正确显示,但执行方式不同

时间:2019-02-01 19:38:41

标签: linux bash scripting

我有以下代码用他们的艺术家标记我的FLAC文件:

#!/bin/bash

# This script gets called with a directory of flac-audio-files to tag
# 
# The files MUST have a filename of format "Artist - Title.flac"
# The whitespaces in the filename-format are optional

for file in $1/*; do
    name=$(echo "$file" | cut -d'/' -f 2)                 # removes leading slashes and dirnames
    artist=$(echo "$name"| cut -d'-' -f 1)                # cuts the artists name out of the name
    artist=$(echo "$artist" | awk '{$1=$1};1')            # removes Whitespaces before and after 
    fname=$(echo "$file" | awk '{gsub(/ /,"\\ ");print}') # Supposed to escape spaces
    fname=$(echo "$file" | awk '{gsub(/\(/,"\\(");print}') # Supposed to escape (
    fname=$(echo "$file" | awk '{gsub(/)/,"\\)");print}') # Supposed to escape )
    echo "metaflac --set-tag=\"ARTIST=$artist\" $fname"
    metaflac --set-tag=\"ARTIST=$artist\" "$fname"  # Tags the Song, finally
done

这将输出命令(带有回显“ metaflac ...”部分),这些命令在通过复制和粘贴执行时可以完美执行,但是回显之后的命令将输出“找不到文件”错误。我想念什么?

编辑: 引用文件名也会导致找不到文件的错误,然后执行单词拼写。

ls "some file with spaces"
"some : File not found!
file : File not found!
with : File not found!
spaces" : File not found!

1 个答案:

答案 0 :(得分:1)

乍一看,我认为您的问题是实际命令中引号的不必要转义,例如--set-tag=\"ARTIST=$artist\"。但是,您得到的错误是该文件不存在。

这是因为您正在修改文件名,然后只是希望该文件存在。但是您实际上尚未重命名该文件。你所做的一切修改的变量fname,其中包含实际文件名,存储在的修改版本file

不清楚在$fname中转义空格和括号的意图是什么,但是无论如何,该文件实际上都不存在。

我怀疑您正在尝试转义括号和空格,以便外壳程序不会抱怨,就像您在命令行中直接输入文件名时的处理方式,例如:

ls  some\ file\ \(with\ spaces\ and\ parentheses\).txt

但是,在脚本中,您无需经历所有麻烦。您只需要确保在命令中使用$file即可引用

metaflac --set-tag="ARTIST=$artist" "$file"

当在文件名两边加上引号时,shell不会尝试对文件名进行单词拆分。此外,企图逃跑的事情像你这样做实际上不会反正工作,因为扩大后壳不会承认你的转义$fname。而是将它们视为只是文字\字符。

例如:

> touch "some file"
> ls -l
-rw-r--r-- 1 user user 0 2019.02.01 12:11 some file
> var="some\ file"
> ls "$var"
ls: cannot access 'some\ file': No such file or directory

即使您删除了$var周围的引号,它仍然无效:

> ls $var
ls: cannot access 'some\': No such file or directory
ls: cannot access 'file': No such file or directory

删除引号引起壳里做的扩展型变量字拆分,但它仍然认为反斜杠作为文字字符,而不是逃避。您可以使用eval使它正常工作(但这仍然不是正确的方法):

> eval "ls -l $var"
-rw-r--r-- 1 user user 0 2019.02.01 12:11 some file

正确的方法是只确保正确引用变量,而不要尝试转义:

> var="some file"  # No need to escape the space
> ls -l "$var"     # Quotes around $var
-rw-r--r-- 1 user user 0 2019.02.01 12:11 some file

您也可以直接在命令行上使用引号,以避免不得不转义:

> ls this\ is\ the\ hard\ way.txt
this is the hard way.txt

> ls "this is the easy way.txt"
this is the easy way.txt