はじめに
記事の概要と目的
iTerm2 は、macOS 向けの強力なターミナルエミュレータです。
多くの開発者やシステム管理者に愛用されています。
今回の記事では、「iTerm2 で複数行の長い文字/コマンドを貼り付けると、正しく貼り付けられない問題」について、その原因と解決策を説明します。
背景
先日、 AWS EC2 の情報を一覧取得するための CLI 生成ツールを作成しました。
パラメータを大量に指定した場合の CLI は非常に長くなります。
aws ec2 describe-instances --query "
Reservations[].Instances[].{
InstanceId: InstanceId,
InstanceName: Tags[?Key==\`Name\`]|[0].Value,
ImageId: ImageId,
InstanceType: InstanceType,
KeyName: KeyName,
…
このように改行を含む長い文字列を iTerm2 に張り付けようとすると、特定の Macbook Air で正常に張り付けられない問題が発生しました。
(Macbook Pro では正常に張り付け可能でした)
もし同様の事象が発生している人がいれば、一助となれば幸いです。
ググってみた限り現状で日本語記事は見当たりませんでしたので記しておきます。
発生している問題
まずはどのような問題が発生しているのか改めて確認します。
問題の詳細
一言で言うと「 iTerm2 に複数行の文字列を貼り付ける際に発生する問題」です。
具体的な例を挙げると、以下のようなコマンドをペーストする場合に発生します。
aws ec2 describe-instances --query "
Reservations[].Instances[].{
InstanceId: InstanceId,
InstanceName: Tags[?Key==\`Name\`]|[0].Value,
ImageId: ImageId,
InstanceType: InstanceType,
KeyName: KeyName,
LaunchTime: LaunchTime,
PublicIpAddress: PublicIpAddress,
PrivateIpAddress: PrivateIpAddress,
State: State.Name,
SubnetId: SubnetId,
VpcId: VpcId,
Architecture: Architecture,
BlockDeviceMappings: join(',', BlockDeviceMappings[].Ebs.VolumeId),
EbsOptimized: EbsOptimized | [0],
EnaSupport: EnaSupport | [0],
Hypervisor: Hypervisor,
IamInstanceProfileArn: IamInstanceProfile.Arn,
IamInstanceProfileId: IamInstanceProfile.Id,
PlacementAvailabilityZone: Placement.AvailabilityZone,
PlacementGroupName: Placement.GroupName,
PlacementTenancy: Placement.Tenancy,
Platform: Platform,
RootDeviceName: RootDeviceName,
RootDeviceType: RootDeviceType,
VirtualizationType: VirtualizationType,
SecurityGroups: join(',', SecurityGroups[].GroupName),
TagsKey: join(',', Tags[].Key),
TagsValue: join(',', Tags[].Value),
CpuOptionsCoreCount: CpuOptions.CoreCount,
CpuOptionsThreadsPerCore: CpuOptions.ThreadsPerCore,
CapacityReservationPreference: CapacityReservationSpecification.CapacityReservationPreference,
HibernationOptionsConfigured: HibernationOptions.Configured | [0],
MetadataOptionsState: MetadataOptions.State,
MetadataOptionsHttpTokens: MetadataOptions.HttpTokens,
MetadataOptionsHttpPutResponseHopLimit: MetadataOptions.HttpPutResponseHopLimit,
MetadataOptionsHttpEndpoint: MetadataOptions.HttpEndpoint,
EnclaveOptionsEnabled: EnclaveOptions.Enabled | [0],
AmiLaunchIndex: AmiLaunchIndex,
MonitoringState: Monitoring.State,
PrivateDnsName: PrivateDnsName,
PublicDnsName: PublicDnsName,
StateTransitionReason: StateTransitionReason,
ProductCodes: join(',', ProductCodes[].ProductCodeId),
ClientToken: ClientToken,
NetworkInterfaceId: join(',', NetworkInterfaces[].NetworkInterfaceId),
NetworkInterfaceStatus: join(',', NetworkInterfaces[].Status),
NetworkInterfaceMacAddress: join(',', NetworkInterfaces[].MacAddress),
NetworkInterfacePrivateDnsName: join(',', NetworkInterfaces[].PrivateDnsName),
NetworkInterfaceDescription: join(',', NetworkInterfaces[].Description),
NetworkInterfaceSourceDestCheck: NetworkInterfaces[].SourceDestCheck | [0],
NetworkInterfaceVpcId: join(',', NetworkInterfaces[].VpcId),
NetworkInterfaceSubnetId: join(',', NetworkInterfaces[].SubnetId),
NetworkInterfaceOwnerId: join(',', NetworkInterfaces[].OwnerId),
NetworkInterfacePrivateIpAddress: join(',', NetworkInterfaces[].PrivateIpAddress),
NetworkInterfacePublicDnsName: join(',', NetworkInterfaces[].Association.PublicDnsName),
NetworkInterfacePublicIp: join(',', NetworkInterfaces[].Association.PublicIp),
BlockDeviceMappingsDeviceName: join(',', BlockDeviceMappings[].DeviceName),
BlockDeviceMappingsEbsDeleteOnTermination: BlockDeviceMappings[].Ebs.DeleteOnTermination | [0],
BlockDeviceMappingsEbsStatus: join(',', BlockDeviceMappings[].Ebs.Status),
BlockDeviceMappingsEbsAttachTime: join(',', BlockDeviceMappings[].Ebs.AttachTime)
}" --output table
上記のような長いコマンドをペーストした場合に本問題が発生します。
例として以下のような問題が発生する場合があります。
- 改行のタイミングがズレる
- 途中で文字が欠ける
- 誤った順序でペーストされる
問題の原因
この章では、なぜこのような問題が発生するのか原因を確認しましょう。
シェルのバッファリング問題
結論、原因はシェルのバッファリングにあります。
シェルは、ユーザーが入力したコマンドを一時的に保存し、実行するためのバッファ(メモリ領域)を持っています。
しかし、このバッファには限界があります。
特に大量のデータを一度に入力しようとすると、シェルがそのデータを適切に処理できないことがあります。
これが、複数行の長いコマンドを貼り付ける際に問題となる主な原因の一つです。
シェルのバッファの動作
シェルのバッファは、以下のように動作します:
- 入力の受け取り: ユーザーが入力する文字列をシェルが受け取ります。
- バッファへの格納: 受け取った文字列を一時的にバッファに格納します。このバッファには、一定のサイズ制限があります。
- コマンドの実行: バッファに格納されたコマンドを解析し、実行します。
バッファの限界
シェルのバッファにはサイズの限界があります。
そのため、一度に大量のデータを入力しようとすると、以下のような問題が発生します:
- バッファオーバーフロー:
- バッファが一杯になると追加のデータを受け取れなくなりデータの一部が失われます。
- データの分割:
- シェルがデータを部分的にしか受け取れないため、コマンドが途中で分割されます。
特に、複数行の長いコマンドを一度にペーストする場合、これらの問題が発生します。
シェルのバッファの問題は、データ I/O 速度やシェルの処理速度にも影響されます。
つまり、システムの性能や負荷状況によっても変動します。
iTerm2 のデフォルト設定
この章では iTerm2 のデフォルト設定を確認しましょう。
デフォルト設定値
iTerm2 のペースト動作に関するデフォルト設定は、以下のようになっています:
- Delay in seconds between chunks when pasting normally:
- この値は、通常のペースト操作時に各チャンク間で待機する時間を指定しています
※チャンク: データの小さな塊 - デフォルト値は 0.01530456
- この値は、通常のペースト操作時に各チャンク間で待機する時間を指定しています
このデフォルト値は、多くのシステムで十分な待機時間(速度)とされます。
しかし、実際に適しているかはマシンの CPU やメモリの処理能力に依ります。
言い換えるなら、性能が低いマシンにとってはこの値は不適です。
例えば、シェルがペーストされた大量のデータを一度に処理しきれず結果としてバッファがオーバーフローしたり、部分的なデータしか受け取れなかったりします。
解決方法
ここでは、問題の解決方法と手順の詳細を確認します。
解決方法の概要
もうお分かりかと思いますが、この問題を解決するためには、ペースト時の各チャンク間の待機時間を調整する必要があります。
例えば、値を10倍( 0.01530456 から 0.1530456 )に変更することで、シェルが各チャンクを適切に受け取って処理する時間を確保できるかもしれません。
人に依る(マシンに依る)ので色々試してみてください。
この設定変更によって、複数行の長いコマンドが正確にペーストされるはずです。
iTerm2 設定変更の手順
この章では具体的な手順を確認しましょう。
iTerm2 を開き Settings を開く
まずは macOS 上で iTerm2 を起動します。
次に、メニューバーの「iTerm2」をクリックし、「Settings…」を選択します。
Advanced タブに移動して “Delay Paste” を検索
- Settings ウィンドウが開いたら、上部にある「Advanced」タブをクリックします。
- 検索ボックスに “Delay Paste” と入力します。
“Delay between sending lines of pasted text” 値を変更
- “Delay between sending lines of pasted text.” 項目を大きくします。
- 以下の例では一桁大きくしました。
設定値を変更したら、ウィンドウを閉じて設定を保存します。
これで、iTerm2のペースト動作が改善されます。
正常にペーストできずシンタックスエラー等が発生していた方は、改善するかご確認ください。
その他の解決方法
「“Delay between sending lines of pasted text.” 項目を大きくしたのに事象が改善しない」という方は以下の方法もご検討下さい。
“Number of bytes to paste in each chunk when pasting normally” 値の変更
“Number of bytes to paste in each chunk when pasting normally.” は、ペースト時に送信されるデータのチャンクサイズを指定するものです。
デフォルト値は 333 バイトです。
例えば、この設定を(極端ですが) 10 バイトに変更することで、一度に送信されるデータ量が大幅に減り、シェルがデータを適切に処理しやすくなります。
小さなチャンクに分割することで、データの受け取りがスムーズになり、コマンドが正常にペーストされます。
先ほどの「Delay in seconds between chunks when pasting normally.」では、値を大きくすることで各チャンク間の待機時間を延長しました。
今回の「Number of bytes to paste in each chunk when pasting normally.」では、値を小さくすることで各チャンクサイズそのものを小さくしている形です。
要するに、いずれもシェルの処理能力が足りない状況を補うための設定です。
スローモードでペーストする
今まで、以下の項目の設定をして事象を改善してきました。
- Delay in seconds between chunks when pasting normally. (default 0.015)
- Number of bytes to paste in each chunk when pasting normally. (default 333)
項目名からも分かる通りですが、これらの項目はノーマルモード (when pasting normally.) で使われるものです。
それらの直下に記載されている以下の項目は、スローモード (when pasting slowly.) で使われるものです。
- Delay in seconds between chunks when pasting slowly. (default 0.125)
- Number of bytes to paste in each chunk when pasting slowly. (default 10)
そのため、スローモードを使用することで上記の設定値が適用されるため、事象が改善するかと思います。
スローモードでペーストする際の手順は以下です。
- Edit > Paste Special > Paste Slowly
※結構ペーストが遅くなります。文字列の量によってはかなり時間がかかるのでご注意ください。
さいごに
今回の問題の根本原因は、iTerm2 が複数行のコマンドをペーストする際にシェルがデータを適切に処理できないことにあります。
この問題に対して、「待機時間の延長」と「チャンクサイズの縮小」のいずれの方法も、シェルがデータを受け取りやすくすることで有効な解決策となりました。
類似の事例としては以下を確認しました。
公式ドキュメントは以下です。
興味があればご参照ください。
以上です。
コメント