mv foo* ~/bar/
のようなコマンドは、foo*
に一致するファイルがない場合、stderrにこのメッセージを生成します。
mv: cannot stat `foo*': No such file or directory
ただし、このケースに取り組んでいるスクリプトでは問題ありません。ログからそのメッセージを省略したいと思います。
何も動かされなかった場合でもmv
が静かになるように伝える良い方法はありますか?
これをお探しですか?
$ mv file dir/
mv: cannot stat ‘file’: No such file or directory
$ mv file dir/ 2>/dev/null
# <---- Silent ----->
実際、私はmv
をミュートするのは良い方法だとは思いません(興味があるかもしれない他のことについても報告するかもしれないことを思い出してください...例:~/bar
)。グロブ式が結果を返さない場合にのみ、ミュートする必要があります。実際には、まったく実行しません。
[ -n "$(shopt -s nullglob; echo foo*)" ] && mv foo* ~/bar/
あまり魅力的ではないように見え、bash
でのみ機能します。
OR
[ 'foo*' = "$(echo foo*)" ] || mv foo* ~/bar/
bash
が設定されたnullglob
にいる場合を除きます。ただし、globパターンの3倍の繰り返しの代償を払うことになります。
find . -maxdepth 1 -name 'foo*' -type f -print0 | xargs -0r mv -t ~/bar/
— GNUのmv
にはニースの「宛先優先」オプション(-t
)があり、xargs
は、入力がない場合(-r
)にコマンドの実行をスキップできます。 -print0
と-0
を使用することで、ファイル名にスペースやその他の「おもしろい」ものが含まれていても、混乱しないようにします。
foo*
を一致するファイル名のリストに展開するのは実際にはシェルであるため、mv
がそれ自体でできることはほとんどないことを認識することが重要です。
ここでの問題は、グロブが一致しない場合、bash
のような一部のシェル(およびその他のほとんどのBourneのようなシェル、そのバグのある動作は70年代後半にBourne Shellによって実際に導入された)がパターンをそのまま渡すことです。コマンドに。
したがって、ここでは、foo*
がどのファイルとも一致しない場合、コマンドを中止するのではなく(事前Bourneシェルやいくつかの最新のシェルのように)、シェルは逐語的なfoo*
ファイルをmv
、基本的にmv
にfoo*
というファイルを移動するように依頼します。
そのファイルは存在しません。一致した場合、実際にはパターンと一致したため、mv
はエラーを報告します。パターンがfoo[xy]
であった場合、mv
がfoox
およびfooy
ファイルではなくfoo[xy]
というファイルを誤って移動した可能性があります。
さて、その問題がないシェル(pre-Bourne、csh、tcsh、fish、zsh、bash -O failglob)でも、mv foo* ~/bar
でエラーが発生しますが、今回はシェル。
foo*
に一致するファイルがない場合にエラーではないと見なし、その場合は何も移動しない場合は、最初にファイルのリストを作成することをお勧めします(次のようなエラーが発生しない方法で)一部のシェルのnullglob
オプションを使用して)、次にmv
を呼び出すだけで、リストは空ではありません。
mv
のエラーを隠すallよりも(2> /dev/null
を追加するのと同じように)mv
は他の理由で失敗します。おそらくその理由を知りたいと思うでしょう。
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
または、無名関数を使用して、一時変数の使用を回避します。
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
zsh
は、Bourneバグのないシェルの1つであり、グロブが一致しない場合(およびnullglob
オプションが有効になっていない場合)は、コマンドを実行せずにエラーを報告します。 、したがって、ここでは、zsh
のエラーを非表示にしてmv
のstderrを復元できるので、mv
エラーがあれば表示されますが、一致しないglobに関するエラーは表示されません:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
または、zargs
を使用することもできます。これにより、foo*
グロブがあまりにも多くのファイルに拡張される場合の問題も回避されます。
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
bash
には、1つのグロブに対してのみnullglob
を有効にする構文がなく、failglob
オプションはnullglob
をキャンセルするため、次のようなものが必要です。
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
または、サブシェルで保存するオプションを設定するには、それらを前に保存し、後で復元する必要があります。
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
yash
(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
fish
魚のシェルでは、nullglobの動作がset
コマンドのデフォルトなので、次のようになります。
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
POSIX nullglob
にはsh
オプションはなく、定位置パラメーター以外の配列はありません。グロブが一致したかどうかを検出するために使用できるトリックがあります:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
foo[*]
とfoo*
の両方のグロブを使用することにより、一致するファイルがない場合と、たまたまfoo*
と呼ばれる1つのファイルがある場合(set -- foo*
はできませんでした)。
私はあなたがbashを使用していると仮定しています。このエラーは、一致しないglobをそれ自体に展開するbashの動作に依存するためです。 (比較すると、zshは一致しないglobを拡張しようとするとエラーを発生させます。)
では、次の回避策についてはどうでしょうか?
ls -d foo* >/dev/null 2>&1 && mv foo* ~/bar/
これは、ls -d foo*
が失敗してもmv
を暗黙的に無視しますが、ls foo*
は成功してもmv
が失敗してもエラーを記録します。 (ls foo*
は、存在しないfoo*
以外の理由(例:権限の不足、FSの問題など)で失敗する可能性があるため、このソリューションではこのような状態は黙って無視されることに注意してください。)
おそらく最善ではありませんが、find
コマンドを使用して、フォルダーが空かどうかを確認できます。
find "foo*" -type f -exec mv {} ~/bar/ \;
あなたは例えばすることができます
mv 1>/dev/null 2>&1 foo* ~/bar/
またはmv foo* ~/bar/ 1&>2
詳細については、次を参照してください。 http://mywiki.wooledge.org/BashFAQ/055
あなたはPerl
で(ポータブルに)カンニングすることができます:
Perl -e 'system "mv foo* ~/bar/" if glob "foo*"'
Perlを使用する場合は、次のようにしてください。
#!/usr/bin/Perl
use strict;
use warnings;
use File::Copy;
my $target = "$ENV{HOME}/bar/";
foreach my $file (<foo*>) {
move $file, $target or warn "Error moving $file to $target: $!\n";
}
またはワンライナーとして:
Perl -MFile::Copy -E 'move $_, "$ENV{HOME}/bar/" or warn "$_: $!\n" for <foo*>'
(move
コマンドの詳細については、 File :: Copy のドキュメントを参照してください。)
代わりに
mv foo* ~/bar/
できるよ
cp foo* ~/bar/
rm foo*
シンプルで読みやすい:)
このコードは、ファイルの場合、ソースの場所にいるときに私のために機能しました。
[ -f ${fileName} ] && mv ${source}/${fileName} ${destination}
ディレクトリの場合
[ -d ${source} ] && mv ${source} ${destination}
mv foo* ~/bar/ 2>/dev/null
上記のコマンドが成功したかどうかは、前のコマンドの終了ステータスで確認できます
command: echo $?
エコーの出力なら$? 0以外の場合は、出力が0の場合にコマンドが失敗したことを意味し、コマンドが成功したことを意味します。