简体   繁体   English

Bash脚本无效的空间符号

[英]Bash script invalid space sign

My goal is it is to gate time in second for last modified file in catalog. 我的目标是将目录中上次修改的文件的时间以秒为单位。

I have catalog with space in name and want to stat it with script. 我的目录名称中带有空格,并希望使用脚本对其进行stat With a terminal I simply use: 使用终端,我只需使用:

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

and works perfectly. 并且完美地工作。 In my bash script i read files one by one from directory /var/www/pre/data/jko/files/ with (this is inside while loop) 在我的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`

And if i fire this script with bash script.sh i got 如果我用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

Or maybe there is simpler solution 也许有更简单的解决方案

Correctly, and efficiently, finding the latest file in a directory 正确有效地在目录中查找最新文件

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

...will put the time in seconds for the most-recently-modified file in the shell variable mtime , and the name of this file in the shell variable filename . ...将把最近修改的文件的时间(以秒为单位)放在shell变量mtime ,并将此文件的名称放在shell变量filename

Moreover, it will work even with files with surprising or intentionally malicious names -- filenames with newline literals in their names, filenames with glob characters, etc. I have a more complete explanation of this idiom and why it works here . 此外,它甚至会用奇怪的或故意的恶意文件名的文件的工作-在其名称中使用新行文字的文件名,与水珠文字等文件名我有这个成语的更完整的解释,为什么它在这里


Why your original code didn't work 为什么您的原始代码不起作用

Now, what was wrong with your original code? 现在,您的原始代码出了什么问题? In short: Literal quotes do not substitute for syntactic quotes . 简而言之: 文字引号不能代替句法引号 Let's go into what this means. 让我们看看这意味着什么。

In /var/www/pre/data/jko/files/My\\ Files , the backslash is syntactic : It's shell syntax. /var/www/pre/data/jko/files/My\\ Files ,反斜杠是语法 :它是shell语法。 When you run stat /var/www/pre/data/jko/files/My\\ Files , the result is a syscall that looks like the following: 当您运行stat /var/www/pre/data/jko/files/My\\ Files ,结果是一个类似于以下内容的syscall:

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

Note how the backslash is gone? 注意反斜杠如何消失了? That's because the shell consumed it when it was parsing the string. 这是因为外壳在解析字符串时会消耗掉它。

The following are all exactly identical: 以下都是完全相同

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

...and they can be expanded as follows: ...并且它们可以扩展如下:

# 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"

In the above, the quotes are again syntactic -- they're telling the shell not to split the result of the variable expansion into multiple separate words or evaluate it as a glob -- not literal , in which case they would be passed to stat as part of its argument. 在上面,引号又是句法的 -告诉外壳程序不要将变量扩展的结果拆分为多个单独的单词或将其评估为glob-而不是文字 ,在这种情况下,它们将传递给stat作为其论点的一部分。


So, what happens when you run s=${s// /'\\ '} ? 那么,当您运行s=${s// /'\\ '}什么? You're putting literal backslashes into the data. 您正在将文字反斜杠放入数据中。

Thereafter: 之后:

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

What happens if you leave out the syntactic double quotes on the expansion? 如果在扩展名上省略了句法双引号怎么办? It's even uglier: 更难看:

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'

That's because unquoted expansion doesn't run through all shell parsing steps; 这是因为未引用的扩展未在所有的shell解析步骤中进行; it only does field splitting and glob expansion. 它仅执行字段拆分和全局扩展。

If you paths contain spaces, quote them all to avoid problems: 如果路径中包含空格,请用引号将它们全部引用以避免出现问题:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM