Один вариант использованияsed
:
for file in *tif; do newname=$(echo "$file" | sed 's/_//;s/\.\([0-9]\)/\1/g'); mv -v "$file" "$newname"; done
'Sep04_17.00.37.tif' -> 'Sep04170037.tif'
'Sep04_17.02.02.tif' -> 'Sep04170202.tif'
'Sep04_17.05.54.tif' -> 'Sep04170554.tif'
'Sep04_17.07.17.tif' -> 'Sep04170717.tif'
'Sep04_17.08.41.tif' -> 'Sep04170841.tif'
Использование mv -v
в примере только для отображения до/после.
Вот мое предложение.
#!/bin/bash
files="empty"
for i in A B C D ; do
for j in B C D ; do
fn="$i$j"
nf="$( echo $fn | rev )"
# if nn is 1 $nf wasn't found in $files
nn=1
for q in $files ; do
if [[ "$q" == "$nf" ]] ; then
nn=0
fi
done
if [[ $nn -eq 1 ]] && [[ "$fn" != "$nf" ]]
then
echo "cat $i.txt $j.txt >$fn.txt"
fi
files="$fn $nf $files"
done
done
Вы можете сохранить файловые аргументы вашей команды find
в массив. Также вы можете sort
их перед сохранением. Здесь использовалось нулевое разделение(-d ''
дляmapfile
(== readarray
), -print0
для find
и -z
для sort
), для чего требуются утилиты GNU.
И делаем для них двойную петлю, i
бежим по всей длине и j
от i+1
до конца, и создаем комбинации. Вы можете обрабатывать там каждую комбинацию аргументов файла.
#!/bin/bash
mapfile -d '' arr < <(find. -type f -name '*.txt' -print0 | sort -z)
for ((i=0; i<"${#arr[@]}"; i++)); do
for ((j=i+1; j<"${#arr[@]}"; j++)); do
printf "Processing files: %s %s\n" "${arr[i]}" "${arr[j]}"
done
done
Processing files:./A.txt./B.txt
Processing files:./A.txt./C.txt
Processing files:./A.txt./D.txt
Processing files:./B.txt./C.txt
Processing files:./B.txt./D.txt
Processing files:./C.txt./D.txt
В вашем конкретном примере для cat
файлов и получения желаемого выходного имени файла (при условии, что все они находятся на одном уровне каталога ), вы можете использовать find... -printf '%f\0'
для печати только имен файлов и удаление подстроки с расширением параметра, для создания команд. Слегка измененная версия с использованием разделителя новой строки для имен файлов:
#!/bin/bash
mapfile -t arr < <(find. -type f -name '*.txt' -printf "%f\n" | sort)
for ((i=0; i<"${#arr[@]}"; i++)); do
for ((j=i+1; j<"${#arr[@]}"; j++)); do
cat "${arr[i]}" "${arr[j]}" > "${arr[i]%.*}${arr[j]}"
done
done
Если вы можете использовать perl
и предположить, что ваши имена файлов «хорошо -ведут себя»:
find... |
perl -0777 -MMath::Combinatorics -anE \
'BEGIN{$,=" "}; say sort(@$_) for (combine(2, @F))' |
sort
Выход, когда A\nB\nC\nD\n
является входом:
A B
A C
A D
B C
B D
C D
Чтобы воссоздать ваш пример (GNU sed):
... |
sed -E 's/([^.]+).([^ ]+) ([^.]+).([^ ]+)/cat \1.\2 \3.\4 > \1\3.\2/'
cat A.txt B.txt > AB.txt
cat A.txt C.txt > AC.txt
cat A.txt D.txt > AD.txt
cat B.txt C.txt > BC.txt
cat B.txt D.txt > BD.txt
cat C.txt D.txt > CD.txt
Который затем можно передать в оболочку для выполнения или сделать с флагом /e
в GNU sed.