set '%s_q1.out %s_q2.out %s_q3.out\n'
:|for d in several directories
do cd -P -- "$d" || ! break
set "$1" "../${PWD##*/}"
{ sed -ne'\|\( \.\./a_a_q[123]\.out\)\{3\}|q;s/.//p'
printf "$@" "$2" "$2"; cut -c2-
} <<-IN >./infile
$(paste -d\ - ./infile)
IN
done
Это должно работать с POSIX sed
и bash
, zsh
, кш
, мкш
оболочка и многие другие. С оболочкой тире
или yash
здесь-документ вряд ли будет подкреплен обычным файлом, поэтому вы не можете полагаться на функцию lseek ()
, необходимую для поддержка совместного использования ввода. В этих случаях вам следует переключиться на одну из вышеупомянутых оболочек.
Если вы используете GNU sed
, вы захотите использовать sed -une
вместо просто sed -ne
.
Вот разбивка:
Сначала мы устанавливаем
аргумент, который мы будем снова и снова использовать в качестве строки формата printf
, и устанавливаем оба параметра $ PWD
и $ OLDPWD
- .
Затем мы начинаем перебирать элементы в нескольких каталогах
. Независимо от того, являются ли это каталоги или символические ссылки, мы получаем физический канонический путь -P
в $ PWD
и устанавливаем
его последний компонент пути в $ 2
.
Следующее, что происходит, происходит внизу при перенаправлении heredoc. paste
считывает все ./ infile
в какой-то безопасный временный файл, который оболочка защитила для нас, добавляя при этом один пробел к каждой строке.Затем оболочка устанавливает для этого временного файла значение stdin, и ./ infile
снова назначается - но на этот раз как stdout.
sed
очень мало редактирует. Пока он не встретит вашу строку соответствия, он удаляет первый символ из каждой строки и p
стирает результаты. Как только он встречает вашу строку, он q
полностью использует ввод - ничего не печатает.
Но printf
печатает ../$ {PWD ## * /} _ q
.out , за которым следует перевод строки в стандартный вывод, а затем вырезать
] берет стандартный ввод там, где sed
оставил его (сразу после строки соответствия) , и считывает остальное, удаляя первый байт из каждой строки ввода.
Таким образом, весь отредактированный ./ infile
сводится к тому месту, откуда он появился, в одном куске.
О, я это проверил.
Я заменил бит нескольких каталогов
на путь / tmp
и сделал ...
{ seq 7
echo '../a_a_q1.out ../a_a_q2.out ../a_a_q3.out'
seq 9 14
printf %s\\n '' '' ''
} >/tmp/infile
... который записал / tmp / infile
, который выглядел так:
1 2 3 4 5 6 7 ../a_a_q1.out ../a_a_q2.out ../a_a_q3.out 9 10 11 12 13 14
После запуска приведенного выше фрагмента кода на / tmp
, хотя ...
cat /tmp/infile
1 2 3 4 5 6 7 ../tmp_q1.out ../tmp_q2.out ../tmp_q3.out 9 10 11 12 13 14
Чтобы ответить на вопрос в заголовке, вы можете "сдвинуть" массив с помощью нотации подстроки/подмассива. Сам shift
работает только с позиционными параметрами.
$ a=(a b c d e)
$ a=("${a[@]:1}")
$ echo "${a[@]}"
b c d e
Аналогично, чтобы «вытолкнуть» последний элемент из массива:a=("${a[@]:0:${#a[@]} - 1}" )
илиunset "a[${#a[@]}-1]"
Так что, если бы вы хотели, вы могли бы сделать это:
a=(foo bar doo)
b=(123 456 789)
while [ "${#a[@]}" -gt 0 ]; do
echo "$a $b"
a=("${a[@]:1}")
b=("${b[@]:1}")
done
Но это портит массивы, а "сдвигающие" присваивания, вероятно, излишне копируют данные, так что обычная индексация может быть лучше .
a=(foo bar doo)
b=(123 456 789)
i=0
while [ "$i" -lt "${#a[@]}" ]; do
echo "${a[i]} ${b[i]}"
i=$((i+1))
done
Или, возможно, вместо этого используйте ассоциативный массив, если вас не волнует порядок элементов. "${!arr[@]}"
дает ключи в неопределенном порядке, возможно, не в том порядке, в котором они были назначены в:
declare -A arr=([foo]=123 [bar]=456 [doo]=789)
for k in "${!arr[@]}"; do
echo "$k ${arr[$k]}"
done
Вопрос, который вы задаете, заключается в том, как использовать ++
для увеличения индекса массива.
Вот так:
folderArray=( sdb sdc sdd sde sdf sdg )
counter=0
for i in disk1 disk2 disk3 disk4 disk5 disk6; do
folder_name=${folderArray[counter++]}
echo mkdir /data/$folder_name
done
Индекс массива (, который находится внутри []
), находится в арифметической среде, поэтому постинкремент(++
)работает.
В вопросе о заголовке используется термин shift
. Сдвиг, подобный позиционным аргументам, может быть выполнен -повторным построением массива (медленным процессом ).
folderArray=( sdb sdc sdd sde sdf sdg )
shiftArray=( "${folderArray[@]}" )
counter=0
for i in disk1 disk2 disk3 disk4 disk5 disk6; do
echo mkdir /data/$shiftArray
shiftArray=( "${shiftArray[@]:1}" )
done
Но кажется проще использовать индексы массива напрямую:
folderArray=( sdb sdc sdd sde sdf sdg )
for((i=0;i<${#folderArray[@]};)); do
echo mkdir /data/"${folderArray[i++]}"
done