linux - Bash 脚本无效空格符号

标签 linux bash shell

我的目标是对目录中最后修改的文件以秒为单位的门控时间。​​

我有一个名称中有空格的目录,想用脚本stat它。对于终端,我只需使用:

sudo stat -c %Y /var/www/pre/data/jko/files/My\ Files

并且工作完美。 在我的 bash 脚本中,我从目录 /var/www/pre/data/jko/files/ 中一个一个地读取文件(这是在 while 循环中)

touch tempFile.txt
#ls sort by last modified date
sudo ls -rt /var/www/pre/data/$line/files/ > tempFile.txt 
# read newest file
outputFile=$(tail -1 tempFile.txt) 
# replace all spaces with "\ " sign
outputFile=$(echo ${outputFile// /"\ "})
outputDirectoryToFile=/var/www/pre/data/$line/files/$outputFile
echo $outputDirectoryToFile
expr `sudo date +%s` - `sudo stat -c %Y $outputDirectoryToFile`

如果我用 bash script.sh 触发这个脚本,我得到了

/var/www/pre/data/jko/files/My\ Files //line from echo
stat: cannot stat '/var/www/pre/data/jko/files/My\': No such file or directory
stat: cannot stat 'Files': No such file or directory
expr: syntax error

或者有更简单的解决方案

最佳答案

正确、高效地找到目录中的最新文件

{ read -r -d ' ' mtime && IFS= read -r -d '' filename; } \
  < <(find /directory -type f -printf '%T@ %p\0' | sort -z -r -n)

...会将最近修改的文件的时间(以秒为单位)放入 shell 变量 mtime 中,并将此文件的名称放入 shell 变量 filename.

此外,它甚至可以处理具有令人惊讶或故意恶意名称的文件——名称中带有换行文字的文件名、带有 glob 字符的文件名等。我对这个习惯用法及其工作原理有更完整的解释 here .


为什么您的原始代码不起作用

现在,您的原始代码有什么问题?简而言之:文字引用不能代替句法引用。让我们来看看这意味着什么。

/var/www/pre/data/jko/files/My\Files 中,反斜杠是 syntactic:这是 shell 语法。当您运行 stat/var/www/pre/data/jko/files/My\Files 时,结果是一个系统调用,如下所示:

execv("/usr/bin/stat", "stat", "/var/www/pre/data/jko/files/My Files")

请注意反斜杠是如何消失的?这是因为 shell 在解析字符串时消耗了它。

以下都是完全相同的:

# each of these assigns the same string to the variable named s
s=Hello\ World
s=Hello" "World
s='Hello World'

...它们可以展开如下:

# this passes the *exact* contents of that variable as an argument to stat, and thus tries
# to stat a file named Hello World (no literal quotes in the name):
stat "$s"

在上面,引号又是句法——它们告诉 shell 不要将变量扩展的结果拆分成多个单独的词或将其评估为一个 glob——不是 < em>literal,在这种情况下,它们将作为参数的一部分传递给 stat


那么,当您运行 s=${s///'\'} 时会发生什么?您正在将 literal 反斜杠放入数据中。

此后:

s="Hello World"
s=${s// /'\ '}    # change string to 'Hello\ World'
stat "$s"         # try to stat a file named 'Hello\ World', with the backslash 

如果在展开式中省略句法双引号会怎样?它甚至更丑陋:

s="Hello World"
s=${s// /'\ '}    # change string to 'Hello\ World'
stat $s           # try to stat a file named 'Hello\', and a second file named 'World'

那是因为不带引号的展开并没有贯穿所有的 shell 解析步骤;它只做字段拆分和全局扩展。

关于linux - Bash 脚本无效空格符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38592536/

相关文章:

bash - 如何为 docker 容器订购 Kafka 启动 shell 脚本?

ruby-on-rails - 为什么使用crontab时无法运行启动延迟作业命令

linux - 使用 grep 搜索以字母 "s"开头的单词

bash - 在文本文件中添加引号

php - 本地主机上的 netcat "Connection refused"

linux - 如何读取上一个命令的输出,然后继续执行下一个命令

linux - 每个进程都有自己的内核堆栈,对吧?

xml - 如何通过 xmllint 使用 XSD 验证 XML 文件

linux - 如何从命令行/tty 启动 GNOME Wayland session ?

mysql - 如何使用 bash 文本处理命令将一个字符的单词元素转换为两个字符的单词元素?