为什么我可以在终端窗口中正常执行命令,但在 bash 脚本中遇到错误?

发布于 2024-12-17 22:04:07 字数 1550 浏览 5 评论 0原文

最近我一直在整理我的音乐库,我试图让一切“看起来”都一样。我的所有歌曲都应类似于 04 John Barleycorn.m4a,但其中一些来自多磁盘集的歌曲看起来类似于 2-04 John Barleycorn.m4a。所以我立即想到,“为什么不制作一个 bash 脚本来为我完成所有这些繁琐的工作呢?”我几乎不知道,我会花更多的时间试图找出这个“错误”,而不是手工完成。只有一个小小的区别:我不会学到任何手工制作的东西!

这是我的脚本:

#!/bin/bash

filename="/tmp/fileout.txt"

find . -name '?-*.???' > $filename

cat $filename | while read line
do
    echo ${line:1}
    newname=$(echo ${line%\/*}/${line#*-})
    echo $newname
    #mv \"$line\" \"$newname\"
done

它应该足够简单,对吧?它找到所有多磁盘格式的文件,并将它们放入文本文件中。然后,每一行都会被读回、重新格式化,并“移动”到其新位置/文件名。 (有些部分被注释掉了,因为我想在移动文件之前确保事情“看起来”不错)但是,当我第一次尝试时(在事情“看起来”不错并删除了前面的 # mv),我一直收到

mv: target `Barleycorn.m4a"' is not a directory

,我认为这是因为空格没有被转义。我认为通过在它周围加上引号可以解决它,但显然不是。

但我稍后会尝试解决这个问题。这是我的越野车问题。我想删除文件名中的第一个字符(句点)(只是一个例子......我实际上不需要出于任何原因这样做):

line="./Traffic/Smiling Phases/04 John Barleycorn.m4a"
echo ${line:1}

通过输入即可正常工作命令行。

但在 bash 脚本中,它的响应如下:

/home/kyleowen/filerenamer.sh: 15: Bad substitution

在使用 ${var//foo/bar/} 和花括号内的其他字符串操作之前,我已经多次收到此错误。

它为什么要这样做?我的脚本是否可以像在命令行中一样有效地运行所有操作?

当然,我希望有一个可以工作的 bash 脚本……但我主要是想问为什么在处理字符串操作时会出现 Bad replacement 错误。谢谢!

编辑:我发现我非常尴尬的错误......我从来没有提到我是如何执行这些脚本的。我将它们作为 sh test.sh 而不是 bash test.sh 执行。我假设 sh 会将它们作为用户的默认 shell 执行,但我想我错了(或者默认 shell 不是 bash)。

感谢您提供有关输入重定向的提示!当我得到有用的东西时,我会发回我所拥有的东西。

I've been organizing my music library as of late, and I'm trying to make everything "look" the same. All my songs should look like 04 John Barleycorn.m4a, but some of them, coming from multi-disk sets, look like 2-04 John Barleycorn.m4a. So I immediately thought, "Why not make a bash script to do all of this tedious work for me?" Little did I know, I would spend more time trying to figure out this "bug" than it would take to just do it by hand. Only one small difference: I wouldn't learn anything doing it by hand!

So here's my script:

#!/bin/bash

filename="/tmp/fileout.txt"

find . -name '?-*.???' > $filename

cat $filename | while read line
do
    echo ${line:1}
    newname=$(echo ${line%\/*}/${line#*-})
    echo $newname
    #mv \"$line\" \"$newname\"
done

It should be simple enough, right? It finds all the files with the multi-disk format, and puts them in a text file. Each line is then read back, reformated, and is "moved" to its new location/file name. (some parts are commented out since I want to make sure things "looked" good before moving files) However, when I first tried it out (after things "looked" good and removed the # in front of mv), I kept getting

mv: target `Barleycorn.m4a"' is not a directory

and I think that's because the spaces are not being escaped. I thought by putting quotes around it would solve it, but apparently not.

But I'll try to fix that later. Here's my buggy issue. I want to remove the first character (a period) in the file name (just an example...I don't really need to do this for any reason):

line="./Traffic/Smiling Phases/04 John Barleycorn.m4a"
echo ${line:1}

works just fine by typing that in command-line.

But in a bash script, it responds with:

/home/kyleowen/filerenamer.sh: 15: Bad substitution

I've gotten this error many times before when using ${var//foo/bar/} and other string operations within curly braces.

Why is it doing this? Doesn't my script effectively run all operations as if they were in command-line?

I would love a working bash script, sure...but I'm mainly asking why I'm getting a Bad substitution error when working with string operations. Thanks!

EDIT: I found my quite embarrassing mistake...never did I mention how I was executing these scripts. I was executing them as sh test.sh instead of bash test.sh. I assumed sh would execute them as your user's default shell, but I guess I'm wrong (or the default shell is not bash).

Thanks for the tips on input redirection! I'll post back what I have when I get something that works.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

度的依靠╰つ 2024-12-24 22:04:07

有许多引用不一致的地方:

while read line
do
     echo "${line:1}"
     newname="${line%\/*}/${line#*-}"
     echo "$newname"
     # mv "$line" "$newname"
done < <(find . -name '?-*.???')

一般建议:使用输入重定向而不是通过管道进入 read

原因:由于管道的原因,while 循环将在子 shell 中执行

There are a number of quoting inconsistencies:

while read line
do
     echo "${line:1}"
     newname="${line%\/*}/${line#*-}"
     echo "$newname"
     # mv "$line" "$newname"
done < <(find . -name '?-*.???')

In general advice: use input redirection instead of piping into read

Reason: the while loop woulld execute in a subshell due to the pipe

我偏爱纯白色 2024-12-24 22:04:07

尝试在 mv 命令行中不使用反斜杠吗?

mv "$line" "$newname"

反斜杠使 mv 查找文件名中带有双引号的文件。

Try it without the backslashes in the mv command line?

mv "$line" "$newname"

The backslashes makes mv look for files with literal double quotes in the filename.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文