Shell 在循环中将文件名与字符串进行比较的脚本问题
Shell Script issue with comparing file name to string in a loop
问题来了。我在 Ubuntu 14.04 服务器上有一个包含超过 100,000K 个文件的目录。我需要在后台处理文件,所以我写了一个 shell 脚本,将文件转换为更大的文件,然后删除该文件。然而,开始发挥作用的问题是,这也是 cats 过程脚本和输出文件。有什么想法吗?
#!/bin/sh
c=0
#loop through 1000 results at 1 time
d=1000
while [ $c -lt $d ]
do
filename=$(`ls | head -n 1`)
#echo $filename
if [ $filename == "process.sh" ]
then
break
fi
if [ $filename == "file.txt" ]
then
break
fi
cat `ls | head -n 1` >> file.txt
rm `ls | head -n 1`
#echo $c
c=`expr $c + 1`
done
我会重写脚本。
#!/bin/bash
c=0
d=1000
for file in $(find . -maxdepth 1 -type f \( ! -name process.sh -a ! -name file.txt \))
do
cat $file >> file.txt
rm $file
c=$((c+1))
if [ $c -eq $d ]; then
break
fi
done
您应该在每个循环中只调用一次 ls | head -n 1
。检查后您再次调用 ls | head -n 1
,结果可能不同(并发 process.sh 仍然 运行 或新文件)。
你想如何在 file.txt
之后列出文件?您正在跳出循环,其他文件将被跳过。不要在继续中更改它,因为你将继续分配 file.txt
到 filename
.
始终为您的变量使用双引号(想想 my file.txt
),并且您可能也想习惯大括号。
假设您的批处理工作正常并且已经处理了最后一个非特殊文件。 "${filename}"
将是空的!因此,从测试 if [ -f "${filename}" ]
开始,这也将解决目录问题。
我真的希望你有删除这些文件的权限,这样你就不会卡在处理同一个文件 1000 次了。
你不应该处理 ls
输出,所以替代
ls | egrep -v "file.txt|process.sh" | head -n 1
只是做错的方式不同而已。
当你得到一个 "${filename}"
并想根据多个字符串检查它时,你可能想使用 case "${filename}" in ... esac
.
当您的文件没有换行符时,您可以使用 find
和 xargs
。
# First test it
find . -type f \( ! -name process.sh -a ! -name file.txt \) 2>/dev/null |
head -10 | xargs -I % sh -c 'echo "File %"; echo "rm -f %"'
# Looking nice?
find . -type f \( ! -name process.sh -a ! -name file.txt \) 2>/dev/null |
head -1000 | xargs -I % sh -c 'cat "%" > file.txt; rm -f "%"'
问题来了。我在 Ubuntu 14.04 服务器上有一个包含超过 100,000K 个文件的目录。我需要在后台处理文件,所以我写了一个 shell 脚本,将文件转换为更大的文件,然后删除该文件。然而,开始发挥作用的问题是,这也是 cats 过程脚本和输出文件。有什么想法吗?
#!/bin/sh
c=0
#loop through 1000 results at 1 time
d=1000
while [ $c -lt $d ]
do
filename=$(`ls | head -n 1`)
#echo $filename
if [ $filename == "process.sh" ]
then
break
fi
if [ $filename == "file.txt" ]
then
break
fi
cat `ls | head -n 1` >> file.txt
rm `ls | head -n 1`
#echo $c
c=`expr $c + 1`
done
我会重写脚本。
#!/bin/bash
c=0
d=1000
for file in $(find . -maxdepth 1 -type f \( ! -name process.sh -a ! -name file.txt \))
do
cat $file >> file.txt
rm $file
c=$((c+1))
if [ $c -eq $d ]; then
break
fi
done
您应该在每个循环中只调用一次 ls | head -n 1
。检查后您再次调用 ls | head -n 1
,结果可能不同(并发 process.sh 仍然 运行 或新文件)。
你想如何在 file.txt
之后列出文件?您正在跳出循环,其他文件将被跳过。不要在继续中更改它,因为你将继续分配 file.txt
到 filename
.
始终为您的变量使用双引号(想想 my file.txt
),并且您可能也想习惯大括号。
假设您的批处理工作正常并且已经处理了最后一个非特殊文件。 "${filename}"
将是空的!因此,从测试 if [ -f "${filename}" ]
开始,这也将解决目录问题。
我真的希望你有删除这些文件的权限,这样你就不会卡在处理同一个文件 1000 次了。
你不应该处理 ls
输出,所以替代
ls | egrep -v "file.txt|process.sh" | head -n 1
只是做错的方式不同而已。
当你得到一个 "${filename}"
并想根据多个字符串检查它时,你可能想使用 case "${filename}" in ... esac
.
当您的文件没有换行符时,您可以使用 find
和 xargs
。
# First test it
find . -type f \( ! -name process.sh -a ! -name file.txt \) 2>/dev/null |
head -10 | xargs -I % sh -c 'echo "File %"; echo "rm -f %"'
# Looking nice?
find . -type f \( ! -name process.sh -a ! -name file.txt \) 2>/dev/null |
head -1000 | xargs -I % sh -c 'cat "%" > file.txt; rm -f "%"'