Проблема с скриптом Bash

Ubuntu 16.04 использует среду рабочего стола Unity, тогда как в 18.04 в настоящее время используется Gnome 3.28.1. Чтобы установить Unity на Ubuntu 18.04, откройте терминал и введите sudo apt update && sudo apt install ubuntu-unity-desktop. Вам будет предоставлен выбор между менеджерами дисплеев. LightDM - это диспетчер отображения по умолчанию для рабочего стола Unity, но любой из них должен работать.

Взгляните на эту ссылку, чтобы получить подробное объяснение. Также посмотрите на NoobsLab. Если вы хотите, чтобы значки док-станции менялись без установки всей рабочей среды. Различные расширения Gnome Shell, такие как Dash to Dock, также позволяют выполнять множество настроек.

1
задан 26 March 2011 в 22:02

27 ответов

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

for f in `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

$ ls -l -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 my?bad.exe -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 space bad.exe $ for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe)

We может настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

$ IFS=""; for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space bad.exe ./my bad.exe)

Как вы можно увидеть, теперь у bash нет правила разбивать строку, возвращаемую командой find, и обрабатывает весь вывод как одно значение.

Ясно, что проблема заключается в том, что если мы используем for f in `find...., мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной командой find.

Теперь ради полноты я покажу вам, как сделать ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие символы разделителя и исправить вашу текущую проблему:

[ f3]

Здесь команда find -name "*.exe" -exec echo -n {}: \; возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и, таким образом, bash выполняет итерацию в последний раз с пустой строкой.

IFS=":"; for f in $(find -name "*.exe" -exec echo -n {}: \;); do if [ ! -z "$f" ]; then rm "$f"; fi; done;

Вы должны также выполнить свой тест basename / dirname в этом цикле , как вы это делали раньше.

Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Получается что команда find сама может выполнять команды для каждого найденного файла.

find -name "*.exe" -exec ./yourscript.sh {} \;

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить его с помощью rm "$1", даже если он содержит новые строки и пробелы .

Команда find также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 26 May 2018 в 00:41
  • 1
    последний пример намного чище, за исключением того, что мне нужно создать два отдельных сценария, чтобы сделать трюк, как насчет функции bash? – c.sokun 1 November 2010 в 17:28
  • 2
    никакие функции bash не могут быть вызваны из find -exec, но вы, возможно, можете попробовать использовать несколько предложений exec, которые выполняют тест с помощью команды «test», а другой, связанный с & lt; code & gt; -a & lt; / code & gt; 'и' boolean operator. – ithkuil 1 November 2010 в 20:04
  • 3
    @ithkuil: в дополнение к опорожнению IFS вам нужно будет использовать set -f для отключения globbing (обычно имена файлов Windows не содержат символов подстановки, но они также не должны содержать символы перевода строки, t полагайтесь на это здесь). @ c.sokun: отдельный сценарий, безусловно, самый простой способ; вы можете использовать sh -c '…', но это требует, чтобы вы были очень уверены в цитировании оболочки (и если бы вы были, вам не нужно было спрашивать). – Gilles 1 November 2010 в 23:25
  • 4
    for f in $(find...); - плохая практика. См. Ловушку 1 в mywiki.wooledge.org/BashPitfalls для объяснения причины, и mywiki.wooledge.org/BashFAQ/020 тоже видят, как это сделать надлежащим образом , – geirha 3 February 2011 в 06:42
  • 5
    Вы забываете о массивах bash. exes=( *.exe ) поступит правильно, если вы расширите его, используя "${exes[@]}". – Mikel 3 February 2011 в 08:08

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

for f in `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

$ ls -l -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 my?bad.exe -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 space bad.exe $ for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe)

We может настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

$ IFS=""; for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space bad.exe ./my bad.exe)

Как вы можно увидеть, теперь у bash нет правила разбивать строку, возвращаемую командой find, и обрабатывает весь вывод как одно значение.

Ясно, что проблема заключается в том, что если мы используем for f in `find...., мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной командой find.

Теперь ради полноты я покажу вам, как сделать ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие символы разделителя и исправить вашу текущую проблему:

$ for f in $(find -name "*.exe" -exec echo -n {}: \;); do echo "ITERATING ($f)"; done; ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING ()

Здесь команда find -name "*.exe" -exec echo -n {}: \; возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и, таким образом, bash выполняет итерацию в последний раз с пустой строкой.

IFS=":"; for f in $(find -name "*.exe" -exec echo -n {}: \;); do if [ ! -z "$f" ]; then rm "$f"; fi; done;

Вы должны также выполнить свой тест basename / dirname в этом цикле , как вы это делали раньше.

Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Получается что команда find сама может выполнять команды для каждого найденного файла.

find -name "*.exe" -exec ./yourscript.sh {} \;

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить его с помощью rm "$1", даже если он содержит новые строки и пробелы .

Команда find также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 25 July 2018 в 22:58

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

for f in `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

$ ls -l -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 my?bad.exe -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 space bad.exe $ for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe)

We может настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

$ IFS=""; for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space bad.exe ./my bad.exe)

Как вы можно увидеть, теперь у bash нет правила разбивать строку, возвращаемую командой find, и обрабатывает весь вывод как одно значение.

Ясно, что проблема заключается в том, что если мы используем for f in `find...., мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной командой find.

Теперь ради полноты я покажу вам, как сделать ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие символы разделителя и исправить вашу текущую проблему:

$ for f in $(find -name "*.exe" -exec echo -n {}: \;); do echo "ITERATING ($f)"; done; ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING ()

Здесь команда find -name "*.exe" -exec echo -n {}: \; возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и, таким образом, bash выполняет итерацию в последний раз с пустой строкой.

IFS=":"; for f in $(find -name "*.exe" -exec echo -n {}: \;); do if [ ! -z "$f" ]; then rm "$f"; fi; done;

Вы должны также выполнить свой тест basename / dirname в этом цикле , как вы это делали раньше.

Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Получается что команда find сама может выполнять команды для каждого найденного файла.

find -name "*.exe" -exec ./yourscript.sh {} \;

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить его с помощью rm "$1", даже если он содержит новые строки и пробелы .

Команда find также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 27 July 2018 в 01:45

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

for f in `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

$ ls -l -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 my?bad.exe -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 space bad.exe $ for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe)

We может настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

$ IFS=""; for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space bad.exe ./my bad.exe)

Как вы можно увидеть, теперь у bash нет правила разбивать строку, возвращаемую командой find, и обрабатывает весь вывод как одно значение.

Ясно, что проблема заключается в том, что если мы используем for f in `find...., мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной командой find.

Теперь ради полноты я покажу вам, как сделать ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие символы разделителя и исправить вашу текущую проблему:

$ for f in $(find -name "*.exe" -exec echo -n {}: \;); do echo "ITERATING ($f)"; done; ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING ()

Здесь команда find -name "*.exe" -exec echo -n {}: \; возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и, таким образом, bash выполняет итерацию в последний раз с пустой строкой.

IFS=":"; for f in $(find -name "*.exe" -exec echo -n {}: \;); do if [ ! -z "$f" ]; then rm "$f"; fi; done;

Вы должны также выполнить свой тест basename / dirname в этом цикле , как вы это делали раньше.

Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Получается что команда find сама может выполнять команды для каждого найденного файла.

find -name "*.exe" -exec ./yourscript.sh {} \;

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить его с помощью rm "$1", даже если он содержит новые строки и пробелы .

Команда find также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 2 August 2018 в 04:21

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

for f in `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

$ ls -l -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 my?bad.exe -rw-r--r-- 1 marko marko 0 2010-11-01 12:06 space bad.exe $ for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe)

We может настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

$ IFS=""; for f in $(find -name "*.exe"); do echo "ITERATING ($f)"; done ITERATING (./space bad.exe ./my bad.exe)

Как вы можно увидеть, теперь у bash нет правила разбивать строку, возвращаемую командой find, и обрабатывает весь вывод как одно значение.

Ясно, что проблема заключается в том, что если мы используем for f in `find...., мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной командой find.

Теперь ради полноты я покажу вам, как сделать ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие символы разделителя и исправить вашу текущую проблему:

$ for f in $(find -name "*.exe" -exec echo -n {}: \;); do echo "ITERATING ($f)"; done; ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING ()

Здесь команда find -name "*.exe" -exec echo -n {}: \; возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и, таким образом, bash выполняет итерацию в последний раз с пустой строкой.

IFS=":"; for f in $(find -name "*.exe" -exec echo -n {}: \;); do if [ ! -z "$f" ]; then rm "$f"; fi; done;

Вы должны также выполнить свой тест basename / dirname в этом цикле , как вы это делали раньше.

Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Получается что команда find сама может выполнять команды для каждого найденного файла.

find -name "*.exe" -exec ./yourscript.sh {} \;

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить его с помощью rm "$1", даже если он содержит новые строки и пробелы .

Команда find также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 4 August 2018 в 20:51

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

для f в `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

 $ ls -l  -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 my? bad.exe -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 пространство плохое.  exe $ для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe) 

Мы могли бы настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

 $ IFS = ""  ;  для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space bad.exe ./my bad.exe) 

Как вы можете видеть, теперь у bash нет никакого правила разбивать строку, возвращаемую командой find, и обрабатывает целое выводить как одно значение.

Ясно, что проблема заключается в том, что если мы используем для f в `find .... , мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной find!

Теперь для полноты я покажу вам, как заставить ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие разделители и исправить вашу текущую проблему:

 $ для f в $ (find -name "* .exe" -exec echo -n {}: \;);  do echo "ITERATING ($ f)";  сделанный;  ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING () 

Здесь find -name "* .exe" -exec echo -n {}: \ ; команда возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и поэтому bash выполняет итерацию в последний раз с пустой строкой.

 IFS = ":";  для f в $ (find -name "* .exe" -exec echo -n {}: \;);  сделайте, если [!  -z "$ f"];  то rm "$ f";  Fi;  сделанный;  

Вы должны быть в состоянии выполнить также свой тест basename / dirname в этом цикле, как и раньше.


Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Оказывается, что команда find сама может выполнять команды для каждого найденного файла.

 find -name "* .exe" -exec.  /yourscript.sh {} \;  

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить с помощью rm "$ 1" , даже если он содержит символы новой строки и пробелы.

find команда также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 6 August 2018 в 04:25

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

для f в `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

 $ ls -l  -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 my? bad.exe -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 пространство плохое.  exe $ для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe) 

Мы могли бы настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

 $ IFS = ""  ;  для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space bad.exe ./my bad.exe) 

Как вы можете видеть, теперь у bash нет никакого правила разбивать строку, возвращаемую командой find, и обрабатывает целое выводить как одно значение.

Ясно, что проблема заключается в том, что если мы используем для f в `find .... , мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной find!

Теперь для полноты я покажу вам, как заставить ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие разделители и исправить вашу текущую проблему:

 $ для f в $ (find -name "* .exe" -exec echo -n {}: \;);  do echo "ITERATING ($ f)";  сделанный;  ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING () 

Здесь find -name "* .exe" -exec echo -n {}: \ ; команда возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и поэтому bash выполняет итерацию в последний раз с пустой строкой.

 IFS = ":";  для f в $ (find -name "* .exe" -exec echo -n {}: \;);  сделайте, если [!  -z "$ f"];  то rm "$ f";  Fi;  сделанный;  

Вы должны быть в состоянии выполнить также свой тест basename / dirname в этом цикле, как и раньше.


Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Оказывается, что команда find сама может выполнять команды для каждого найденного файла.

 find -name "* .exe" -exec.  /yourscript.sh {} \;  

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить с помощью rm "$ 1" , даже если он содержит символы новой строки и пробелы.

find команда также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 7 August 2018 в 22:32

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

для f в `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

 $ ls -l  -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 my? bad.exe -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 пространство плохое.  exe $ для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe) 

Мы могли бы настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

 $ IFS = ""  ;  для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space bad.exe ./my bad.exe) 

Как вы можете видеть, теперь у bash нет никакого правила разбивать строку, возвращаемую командой find, и обрабатывает целое выводить как одно значение.

Ясно, что проблема заключается в том, что если мы используем для f в `find .... , мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной find!

Теперь для полноты я покажу вам, как заставить ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие разделители и исправить вашу текущую проблему:

 $ для f в $ (find -name "* .exe" -exec echo -n {}: \;);  do echo "ITERATING ($ f)";  сделанный;  ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING () 

Здесь find -name "* .exe" -exec echo -n {}: \ ; команда возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и поэтому bash выполняет итерацию в последний раз с пустой строкой.

 IFS = ":";  для f в $ (find -name "* .exe" -exec echo -n {}: \;);  сделайте, если [!  -z "$ f"];  то rm "$ f";  Fi;  сделанный;  

Вы должны быть в состоянии выполнить также свой тест basename / dirname в этом цикле, как и раньше.


Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Оказывается, что команда find сама может выполнять команды для каждого найденного файла.

 find -name "* .exe" -exec.  /yourscript.sh {} \;  

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить с помощью rm "$ 1" , даже если он содержит символы новой строки и пробелы.

find команда также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 10 August 2018 в 10:40

У Bash есть специальная переменная IFS.

используется bash, чтобы знать, как разбить строку на список файлов. (Внутренний разделитель полей)

По умолчанию он содержит пробел, табуляцию и новую строку.

для f в `find ... будет разделяться на символы, содержащиеся в переменной $ IFS. Если в именах файлов, возвращаемых командой find, есть новая строка или пробел, она будет рассматриваться как другое имя файла, и, таким образом, цикл будет выполняться для каждой части имени.

 $ ls -l  -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 my? bad.exe -rw-r - r-- 1 marko marko 0 2010-11-01 12:06 пространство плохое.  exe $ для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space) ITERATING (bad.exe) ITERATING (./my) ITERATING (bad.exe) 

Мы могли бы настроить переменную $ IFS, но это сложно. Давайте посмотрим, почему:

(Проверьте этот код в сценариях, чтобы изменение переменной IFS не осталось в вашей оболочке, вы можете запутаться)

 $ IFS = ""  ;  для f в $ (find -name "* .exe");  do echo "ITERATING ($ f)";  done (./space bad.exe ./my bad.exe) 

Как вы можете видеть, теперь у bash нет никакого правила разбивать строку, возвращаемую командой find, и обрабатывает целое выводить как одно значение.

Ясно, что проблема заключается в том, что если мы используем для f в `find .... , мы не можем отличить новую строку, содержащуюся в файле, от новой строки, сгенерированной find!

Теперь для полноты я покажу вам, как заставить ваш подход работать, но, пожалуйста, см. более легкое решение в конце ответа.

Мы могли бы использовать другие разделители и исправить вашу текущую проблему:

 $ для f в $ (find -name "* .exe" -exec echo -n {}: \;);  do echo "ITERATING ($ f)";  сделанный;  ITERATING (./space bad.exe) ITERATING (./my bad.exe) ITERATING () 

Здесь find -name "* .exe" -exec echo -n {}: \ ; команда возвращает список файлов, разделенных символом «:» (которые не являются законными в именах файлов Windows).

Теперь следующим шагом было бы фактически удалить эти файлы. Учитывайте, что последний файл заканчивается символом «:», и поэтому bash выполняет итерацию в последний раз с пустой строкой.

 IFS = ":";  для f в $ (find -name "* .exe" -exec echo -n {}: \;);  сделайте, если [!  -z "$ f"];  то rm "$ f";  Fi;  сделанный;  

Вы должны быть в состоянии выполнить также свой тест basename / dirname в этом цикле, как и раньше.


Однако это решение является уродливым и работает только потому, что мы имеем символ, на который мы можем положиться.

Оказывается, что команда find сама может выполнять команды для каждого найденного файла.

 find -name "* .exe" -exec.  /yourscript.sh {} \;  

Затем yourscript.sh wil lget полное имя в $ 1, и вы можете удалить с помощью rm "$ 1" , даже если он содержит символы новой строки и пробелы.

find команда также может использоваться для выполнения встроенного теста basename / dirname внутри вашего скрипта, но это более продвинутая тема.

5
ответ дан 13 August 2018 в 17:12
  • 1
    последний пример намного чище, за исключением того, что мне нужно создать два отдельных сценария, чтобы сделать трюк, как насчет функции bash? – c.sokun 1 November 2010 в 17:28
  • 2
    никакие функции bash не могут быть вызваны из find -exec, но вы, возможно, можете попробовать использовать несколько предложений exec, которые выполняют тест с помощью команды «test», а другой, связанный с & lt; code & gt; -a & lt; / code & gt; 'и' boolean operator. – ithkuil 1 November 2010 в 20:04
  • 3
    @ithkuil: в дополнение к опорожнению IFS вам нужно использовать set -f , чтобы отключить глобусы (обычно имена файлов Windows не содержат символов подстановки, я тоже не должен содержать новые строки, поэтому вы не можете полагаться на это здесь). @ c.sokun: отдельный сценарий, безусловно, самый простой способ; вы можете использовать sh -c '...' , но это требует, чтобы вы были очень уверены в цитировании оболочки (и если бы вы были, вам не нужно было спрашивать). – Gilles 1 November 2010 в 23:25
  • 4
    для f в $ (find ...); - плохая практика. См. Ловушку 1 в mywiki.wooledge.org/BashPitfalls для объяснения причины, и mywiki.wooledge.org/BashFAQ/020 тоже видят, как это сделать надлежащим образом , – geirha 3 February 2011 в 06:42
  • 5
    Вы забываете о массивах bash. exes = (* .exe) поступит правильно, если вы расширите его, используя "$ {exes [@]}" . – Mikel 3 February 2011 в 08:08

Вы действительно можете использовать ( *.exe ) для решения этой проблемы в bash.

Помещение круглых скобок, подобных этому ( и ) вокруг шаблона, означает, что оно будет расширено и сохранено в array.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

exes=( *.exe )
for exe in "${exes[@]}"; do
    echo "'$exe'"
done

Вот полный пример:

$ mkdir 'dir
> with
> spaces'
$ touch 'dir
> with
> spaces/dir
> with
> spaces'
$ touch 'dir
> with
> spaces/other
> file'
$ find .
.
./dir?with?spaces
./dir?with?spaces/dir?with?spaces
./dir?with?spaces/other?file
$ cd 'dir
> with
> spaces'
$ files=( * )
$ for file in "${files[@]}"; do
> echo "'$file'"
> done
'dir
with
spaces'
'other
file'

I может предоставить только полное решение после того, как вы выясните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 26 May 2018 в 00:41

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая новые строки.

#!/bin/bash

if (($# != 1)); then
     echo >&2 "Usage: $0 directory"
     exit 1
fi

while IFS= read -r -d '' file; do 
    base=${file##*/} dir=${file%/*/*}
    if [[ $dir/${base%.exe}/$base -ef $file ]]; then
        echo rm "$file"
    fi
done < <(find "$1" -type f -name "*.exe" -print0)

См. http://mywiki.wooledge.org/BashFAQ/020 и http: //mywiki.wooledge .org / BashFAQ / 100 для более подробной информации.

2
ответ дан 26 May 2018 в 00:41
  • 1
    Я не уверен, что работает. Ваш код подсказывает, что IFS= и -print0 будут работать вместе, но они не отображаются, когда я запускаю find . -print0 | while IFS= read -r file; do echo "'$file'"; done. – Mikel 3 February 2011 в 08:16
  • 2
    Вы правы, мне не удалось скопировать его. Чтение отсутствовало в -d '', чтобы сказать, что строки заканчиваются на \0 вместо \n. Исправлено в ответе. – geirha 3 February 2011 в 14:22
  • 3
    вы должны иметь -d $'\0' – glenn jackman 27 March 2011 в 05:00
  • 4
    @glenn jackman $'\0' расширяется до того же самого, что и ''. Bash записывается на C и внутри, переменные хранятся как C-строки (char []). C-строки заканчиваются NUL-байтом (\ 0). параметр read--d использует первый символ следующего аргумента, который для пустой строки будет NUL-байтом. – geirha 27 March 2011 в 05:54

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая новые строки.

#!/bin/bash if (($# != 1)); then echo >&2 "Usage: $0 directory" exit 1 fi while IFS= read -r -d '' file; do base=${file##*/} dir=${file%/*/*} if [[ $dir/${base%.exe}/$base -ef $file ]]; then echo rm "$file" fi done < <(find "$1" -type f -name "*.exe" -print0)

См. http://mywiki.wooledge.org/BashFAQ/020 и http: //mywiki.wooledge .org / BashFAQ / 100 для более подробной информации.

2
ответ дан 25 July 2018 в 22:58
  • 1
    Я не уверен, что работает. Ваш код подсказывает, что IFS= и -print0 будут работать вместе, но они не отображаются, когда я запускаю find . -print0 | while IFS= read -r file; do echo "'$file'"; done. – Mikel 3 February 2011 в 08:16
  • 2
    Вы правы, мне не удалось скопировать его. Чтение отсутствовало в -d '', чтобы сказать, что строки заканчиваются на \0 вместо \n. Исправлено в ответе. – geirha 3 February 2011 в 14:22
  • 3
    вы должны иметь -d $'\0' – glenn jackman 27 March 2011 в 05:00
  • 4
    @glenn jackman $'\0' расширяется до того же самого, что и ''. Bash записывается на C и внутри, переменные хранятся как C-строки (char []). C-строки заканчиваются NUL-байтом (\ 0). параметр read--d использует первый символ следующего аргумента, который для пустой строки будет NUL-байтом. – geirha 27 March 2011 в 05:54

Вы действительно можете использовать ( *.exe ) для решения этой проблемы в bash.

Помещение круглых скобок, подобных этому ( и ) вокруг шаблона, означает, что оно будет расширено и сохранено в array.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

exes=( *.exe ) for exe in "${exes[@]}"; do echo "'$exe'" done

Вот полный пример:

$ mkdir 'dir > with > spaces' $ touch 'dir > with > spaces/dir > with > spaces' $ touch 'dir > with > spaces/other > file' $ find . . ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir > with > spaces' $ files=( * ) $ for file in "${files[@]}"; do > echo "'$file'" > done 'dir with spaces' 'other file'

I может предоставить только полное решение после того, как вы выясните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 25 July 2018 в 22:58

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая новые строки.

#!/bin/bash if (($# != 1)); then echo >&2 "Usage: $0 directory" exit 1 fi while IFS= read -r -d '' file; do base=${file##*/} dir=${file%/*/*} if [[ $dir/${base%.exe}/$base -ef $file ]]; then echo rm "$file" fi done < <(find "$1" -type f -name "*.exe" -print0)

См. http://mywiki.wooledge.org/BashFAQ/020 и http: //mywiki.wooledge .org / BashFAQ / 100 для более подробной информации.

2
ответ дан 27 July 2018 в 01:45
  • 1
    Я не уверен, что работает. Ваш код подсказывает, что IFS= и -print0 будут работать вместе, но они не отображаются, когда я запускаю find . -print0 | while IFS= read -r file; do echo "'$file'"; done. – Mikel 3 February 2011 в 08:16
  • 2
    Вы правы, мне не удалось скопировать его. Чтение отсутствовало в -d '', чтобы сказать, что строки заканчиваются на \0 вместо \n. Исправлено в ответе. – geirha 3 February 2011 в 14:22
  • 3
    вы должны иметь -d $'\0' – glenn jackman 27 March 2011 в 05:00
  • 4
    @glenn jackman $'\0' расширяется до того же самого, что и ''. Bash записывается на C и внутри, переменные хранятся как C-строки (char []). C-строки заканчиваются NUL-байтом (\ 0). параметр read--d использует первый символ следующего аргумента, который для пустой строки будет NUL-байтом. – geirha 27 March 2011 в 05:54

Вы действительно можете использовать ( *.exe ) для решения этой проблемы в bash.

Помещение круглых скобок, подобных этому ( и ) вокруг шаблона, означает, что оно будет расширено и сохранено в array.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

exes=( *.exe ) for exe in "${exes[@]}"; do echo "'$exe'" done

Вот полный пример:

$ mkdir 'dir > with > spaces' $ touch 'dir > with > spaces/dir > with > spaces' $ touch 'dir > with > spaces/other > file' $ find . . ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir > with > spaces' $ files=( * ) $ for file in "${files[@]}"; do > echo "'$file'" > done 'dir with spaces' 'other file'

I может предоставить только полное решение после того, как вы выясните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 27 July 2018 в 01:45

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая новые строки.

#!/bin/bash if (($# != 1)); then echo >&2 "Usage: $0 directory" exit 1 fi while IFS= read -r -d '' file; do base=${file##*/} dir=${file%/*/*} if [[ $dir/${base%.exe}/$base -ef $file ]]; then echo rm "$file" fi done < <(find "$1" -type f -name "*.exe" -print0)

См. http://mywiki.wooledge.org/BashFAQ/020 и http: //mywiki.wooledge .org / BashFAQ / 100 для более подробной информации.

2
ответ дан 2 August 2018 в 04:21
  • 1
    Я не уверен, что работает. Ваш код подсказывает, что IFS= и -print0 будут работать вместе, но они не отображаются, когда я запускаю find . -print0 | while IFS= read -r file; do echo "'$file'"; done. – Mikel 3 February 2011 в 08:16
  • 2
    Вы правы, мне не удалось скопировать его. Чтение отсутствовало в -d '', чтобы сказать, что строки заканчиваются на \0 вместо \n. Исправлено в ответе. – geirha 3 February 2011 в 14:22
  • 3
    вы должны иметь -d $'\0' – glenn jackman 27 March 2011 в 05:00
  • 4
    @glenn jackman $'\0' расширяется до того же самого, что и ''. Bash записывается на C и внутри, переменные хранятся как C-строки (char []). C-строки заканчиваются NUL-байтом (\ 0). параметр read--d использует первый символ следующего аргумента, который для пустой строки будет NUL-байтом. – geirha 27 March 2011 в 05:54

Вы действительно можете использовать ( *.exe ) для решения этой проблемы в bash.

Помещение круглых скобок, подобных этому ( и ) вокруг шаблона, означает, что оно будет расширено и сохранено в array.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

exes=( *.exe ) for exe in "${exes[@]}"; do echo "'$exe'" done

Вот полный пример:

$ mkdir 'dir > with > spaces' $ touch 'dir > with > spaces/dir > with > spaces' $ touch 'dir > with > spaces/other > file' $ find . . ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir > with > spaces' $ files=( * ) $ for file in "${files[@]}"; do > echo "'$file'" > done 'dir with spaces' 'other file'

I может предоставить только полное решение после того, как вы выясните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 2 August 2018 в 04:21

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая новые строки.

#!/bin/bash if (($# != 1)); then echo >&2 "Usage: $0 directory" exit 1 fi while IFS= read -r -d '' file; do base=${file##*/} dir=${file%/*/*} if [[ $dir/${base%.exe}/$base -ef $file ]]; then echo rm "$file" fi done < <(find "$1" -type f -name "*.exe" -print0)

См. http://mywiki.wooledge.org/BashFAQ/020 и http: //mywiki.wooledge .org / BashFAQ / 100 для более подробной информации.

2
ответ дан 4 August 2018 в 20:51
  • 1
    Я не уверен, что работает. Ваш код подсказывает, что IFS= и -print0 будут работать вместе, но они не отображаются, когда я запускаю find . -print0 | while IFS= read -r file; do echo "'$file'"; done. – Mikel 3 February 2011 в 08:16
  • 2
    Вы правы, мне не удалось скопировать его. Чтение отсутствовало в -d '', чтобы сказать, что строки заканчиваются на \0 вместо \n. Исправлено в ответе. – geirha 3 February 2011 в 14:22
  • 3
    вы должны иметь -d $'\0' – glenn jackman 27 March 2011 в 05:00
  • 4
    @glenn jackman $'\0' расширяется до того же самого, что и ''. Bash записывается на C и внутри, переменные хранятся как C-строки (char []). C-строки заканчиваются NUL-байтом (\ 0). параметр read--d использует первый символ следующего аргумента, который для пустой строки будет NUL-байтом. – geirha 27 March 2011 в 05:54

Вы действительно можете использовать ( *.exe ) для решения этой проблемы в bash.

Помещение круглых скобок, подобных этому ( и ) вокруг шаблона, означает, что оно будет расширено и сохранено в array.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

exes=( *.exe ) for exe in "${exes[@]}"; do echo "'$exe'" done

Вот полный пример:

$ mkdir 'dir > with > spaces' $ touch 'dir > with > spaces/dir > with > spaces' $ touch 'dir > with > spaces/other > file' $ find . . ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir > with > spaces' $ files=( * ) $ for file in "${files[@]}"; do > echo "'$file'" > done 'dir with spaces' 'other file'

I может предоставить только полное решение после того, как вы выясните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 4 August 2018 в 20:51

Вы действительно можете использовать (* .exe) , чтобы решить эту проблему в bash .

Помещая скобки, подобные этому ( и ) вокруг шаблона означает, что он будет расширен и сохранен в массиве.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

  exes = (* .exe) для exe в "$ {exes [@]}";  do echo "'$ exe'" done  

Вот полный пример:

  $ mkdir 'dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / другие & gt;  file '$ find.  ,  ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir & gt;  с & gt;  space '$ files = (*) $ для файла в "$ {files [@]}";  do & gt;  echo "'$ file'" & gt;  done 'dir with spaces' 'other file'  

Я могу только предоставить полное решение после того, как вы уточните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 6 August 2018 в 04:25

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая символы новой строки.

  #! / bin / bash if (($ #! = 1));  затем echo & gt; & amp; 2 "Usage: $ 0 directory" exit 1 fi while IFS = read -r -d '' file;  do base = $ {file ## * /} dir = $ {file% / * / *}, если [[$ dir / $ {base% .exe} / $ base -ef $ file]];  то echo rm "$ file" fi done & lt;  & lt; (find "$ 1" -type f -name "* .exe" -print0)  

См. http://mywiki.wooledge.org/BashFAQ/020 и http://mywiki.wooledge.org/BashFAQ/100 для дальнейшей разработки.

2
ответ дан 6 August 2018 в 04:25

Вы действительно можете использовать (* .exe) , чтобы решить эту проблему в bash .

Помещая скобки, подобные этому ( и ) вокруг шаблона означает, что он будет расширен и сохранен в массиве.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

  exes = (* .exe) для exe в "$ {exes [@]}";  do echo "'$ exe'" done  

Вот полный пример:

  $ mkdir 'dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / другие & gt;  file '$ find.  ,  ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir & gt;  с & gt;  space '$ files = (*) $ для файла в "$ {files [@]}";  do & gt;  echo "'$ file'" & gt;  done 'dir with spaces' 'other file'  

Я могу только предоставить полное решение после того, как вы уточните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 7 August 2018 в 22:32

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая символы новой строки.

  #! / bin / bash if (($ #! = 1));  затем echo & gt; & amp; 2 "Usage: $ 0 directory" exit 1 fi while IFS = read -r -d '' file;  do base = $ {file ## * /} dir = $ {file% / * / *}, если [[$ dir / $ {base% .exe} / $ base -ef $ file]];  то echo rm "$ file" fi done & lt;  & lt; (find "$ 1" -type f -name "* .exe" -print0)  

См. http://mywiki.wooledge.org/BashFAQ/020 и http://mywiki.wooledge.org/BashFAQ/100 для дальнейшей разработки.

2
ответ дан 7 August 2018 в 22:32

Вы действительно можете использовать (* .exe) , чтобы решить эту проблему в bash .

Помещая скобки, подобные этому ( и ) вокруг шаблона означает, что он будет расширен и сохранен в массиве.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

  exes = (* .exe) для exe в "$ {exes [@]}";  do echo "'$ exe'" done  

Вот полный пример:

  $ mkdir 'dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / другие & gt;  file '$ find.  ,  ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir & gt;  с & gt;  space '$ files = (*) $ для файла в "$ {files [@]}";  do & gt;  echo "'$ file'" & gt;  done 'dir with spaces' 'other file'  

Я могу только предоставить полное решение после того, как вы уточните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 10 August 2018 в 10:40

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая символы новой строки.

  #! / bin / bash if (($ #! = 1));  затем echo & gt; & amp; 2 "Usage: $ 0 directory" exit 1 fi while IFS = read -r -d '' file;  do base = $ {file ## * /} dir = $ {file% / * / *}, если [[$ dir / $ {base% .exe} / $ base -ef $ file]];  то echo rm "$ file" fi done & lt;  & lt; (find "$ 1" -type f -name "* .exe" -print0)  

См. http://mywiki.wooledge.org/BashFAQ/020 и http://mywiki.wooledge.org/BashFAQ/100 для дальнейшей разработки.

2
ответ дан 10 August 2018 в 10:40

Вы действительно можете использовать (* .exe) , чтобы решить эту проблему в bash .

Помещая скобки, подобные этому ( и ) вокруг шаблона означает, что он будет расширен и сохранен в массиве.

Затем вы можете перебирать каждый элемент массива, используя что-то вроде этого:

  exes = (* .exe) для exe в "$ {exes [@]}";  do echo "'$ exe'" done  

Вот полный пример:

  $ mkdir 'dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / dir & gt;  с & gt;  пробелы '$ touch' dir & gt;  с & gt;  пробелы / другие & gt;  file '$ find.  ,  ./dir?with?spaces ./dir?with?spaces/dir?with?spaces ./dir?with?spaces/other?file $ cd 'dir & gt;  с & gt;  space '$ files = (*) $ для файла в "$ {files [@]}";  do & gt;  echo "'$ file'" & gt;  done 'dir with spaces' 'other file'  

Я могу только предоставить полное решение после того, как вы уточните, как выглядит ваша структура каталогов, потому что я не уверен, что current_dir_name делает то, что вы думаете.

2
ответ дан 13 August 2018 в 17:12

Это будет обрабатывать имена файлов, содержащие любой символ, разрешенный в имени файла, включая символы новой строки.

  #! / bin / bash if (($ #! = 1));  затем echo & gt; & amp; 2 "Usage: $ 0 directory" exit 1 fi while IFS = read -r -d '' file;  do base = $ {file ## * /} dir = $ {file% / * / *}, если [[$ dir / $ {base% .exe} / $ base -ef $ file]];  то echo rm "$ file" fi done & lt;  & lt; (find "$ 1" -type f -name "* .exe" -print0)  

См. http://mywiki.wooledge.org/BashFAQ/020 и http://mywiki.wooledge.org/BashFAQ/100 для дальнейшей разработки.

2
ответ дан 13 August 2018 в 17:12
  • 1
    Я не уверен, что работает. Ваш код предлагает IFS = и -print0 будут работать вместе, но они не выглядят, когда я запускаю find. -print0 | в то время как IFS = read -r file; do echo & quot; '$ file' & quot ;; сделал . – Mikel 3 February 2011 в 08:16
  • 2
    Вы правы, мне не удалось скопировать его. Чтение отсутствовало в -d '' , чтобы сказать, что строки заканчиваются на \ 0 вместо \n . Исправлено в ответе. – geirha 3 February 2011 в 14:22
  • 3
    вы должны иметь -d $ '\ 0' [! ​​d0] – glenn jackman 27 March 2011 в 05:00
  • 4
    @glenn jackman $ '\ 0' [! ​​d0] расширяется до той же самой вещи, что и '' . Bash записывается на C и внутри, переменные хранятся как C-строки (char []). C-строки заканчиваются NUL-байтом (\ 0). параметр read--d использует первый символ следующего аргумента, который для пустой строки будет NUL-байтом. – geirha 27 March 2011 в 05:54

Другие вопросы по тегам:

Похожие вопросы: