linux - 命令显示正确,但执行方式不同
问题描述
我有以下代码用他们的艺术家标记我的 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
这会输出命令(带有 echo "metaflac ..." 部分),当通过复制和粘贴执行时可以完美执行,但是在 echo 之后的命令会输出“找不到文件”-错误。我错过了什么?
编辑:引用文件名也会给出文件未找到错误,然后执行单词分割。
ls "some file with spaces"
"some : File not found!
file : File not found!
with : File not found!
spaces" : File not found!
解决方案
乍一看,我认为您的问题是实际命令中不必要的引号转义,例如--set-tag=\"ARTIST=$artist\"
. 但是,您得到的错误是该文件不存在。
这是因为您正在修改文件名,然后只是希望该文件存在。但是您实际上并没有重命名该文件。您所做的只是修改了变量fname
,其中包含实际文件名的修改版本,该文件名存储在file
.
目前尚不清楚您转义 中的空格和括号的意图是什么$fname
,但无论如何,该文件实际上并不存在。
我怀疑您正在尝试转义括号和空格,以便外壳不会抱怨,就像您在命令行上直接输入文件名时所做的那样,例如:
ls some\ file\ \(with\ spaces\ and\ parentheses\).txt
但是,在您的脚本中,您不需要经历所有这些麻烦。您只需要确保$file
在命令中使用它时引用它:
metaflac --set-tag="ARTIST=$artist" "$file"
当您在文件名周围加上引号时,shell 不会尝试对文件名进行分词。此外,尝试逃避像你正在做的事情实际上并不会奏效,因为 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
删除引号会导致 shell 对扩展变量进行分词,但它仍然将反斜杠视为文字字符而不是转义符。您可以使用它来使其工作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
推荐阅读
- .net-core - NSwagStudio 生成的客户端无效
- python - 通过切片旧列表创建的新列表;修改“新”也会改变“旧”?
- f# - 如何在 F# 中声明只有一个文字属性的多个文字?
- javascript - 无法使用 GAS 为单元格正确添加值
- android - MessagingAnalytics 中的 Android Firebase 崩溃
- c - C 是否像 python 一样支持 a , b = 0, 1 类型的多重赋值?
- json - 用飞镖映射 Json
- php - PHP通过分组循环遍历数据和打印部分
- c# - Azure service Bus Exception on trye to complete message
- sql - 需要根据表中的唯一值将一列分解为多列?