在bash中删除另一个列表中的项目

时间:2018-02-14 16:25:55

标签: bash shell unix

我正在尝试下面,

processed_files_list='file2 file6'
input_files='file1 file2 file3 file4 file5 file6 file7'
for i in `echo $processed_files_list`
do
    echo "removing '$i'"
    input_files_new=${input_files//$i/}
done
echo $input_files_new

输出:

removing 'file2'
removing 'file6'
[user@desk ~]$ echo $input_files_new
file1 file2 file3 file4 file5 file7

但上面没有删除第一部分,在这种情况下它是 file2 ...为什么会发生这种情况?

2 个答案:

答案 0 :(得分:4)

这是您问题的简单版本:

files="foo"
files_new="$files bar"
files_new="$files baz"
echo "$files_new"

此输出

foo baz

那么bar发生了什么?

这些更改被覆盖,因为您复制并修改了原始列表而不是工作列表。因此,您只能看到最新的更改,而不是累积的更改。

您可以先设置

来解决这个问题
input_files_new="$input_files"

然后每次都更新该列表:

input_files_new=${input_files_new//$i/}

但是,您应该考虑使用正确的数组,因为替换字符串中的file1也会影响file10

答案 1 :(得分:3)

作为一种更好的练习方法,它将使用包含空格的名称,包含通配符的名称,作为其他名称的子串的名称,以及其他更奇怪的角落情况:

processed_files_list=( file2 file6 )
input_files=( file1 file2 file3 file4 file5 file6 file7 )

# create an associative array with filenames as keys, and a fixed value
declare -A input_files_new=( ) # requires bash 4.0 or later
for f in "${input_files[@]}"; do
  input_files_new[$f]=1
done

# remove keys associated with files you don't want
for f in "${processed_files_list[@]}"; do
  unset "input_files_new[$f]"
done

# Print shell-quoted version of the keys from that associative array.    
printf '%q\n' "${!input_files_new[@]}"